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/PlainDate | |
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/PlainDate')
800 files changed, 22408 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-convert.js new file mode 100644 index 0000000000..678c6a5f00 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-convert.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.plaindate +description: PlainDate constructor with non-integer arguments. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(2020.6, 11.7, 24.1), + 2020, 11, "M11", 24, "positive fractional"); + +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(-2020.6, 11.7, 24.1), + -2020, 11, "M11", 24, "negative fractional"); + +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(null, 11, 24), + 0, 11, "M11", 24, "null"); + +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(true, 11, 24), + 1, 11, "M11", 24, "boolean"); + +TemporalHelpers.assertPlainDate(new Temporal.PlainDate("2020.6", "11.7", "24.1"), + 2020, 11, "M11", 24, "fractional strings"); + +for (const invalid of [Symbol(), 1n]) { + assert.throws(TypeError, () => new Temporal.PlainDate(invalid, 11, 24), `year ${typeof invalid}`); + assert.throws(TypeError, () => new Temporal.PlainDate(2020, invalid, 24), `month ${typeof invalid}`); + assert.throws(TypeError, () => new Temporal.PlainDate(2020, 11, invalid), `day ${typeof invalid}`); +} + +for (const invalid of [undefined, "invalid"]) { + assert.throws(RangeError, () => new Temporal.PlainDate(invalid, 11, 24), `year ${typeof invalid}`); + assert.throws(RangeError, () => new Temporal.PlainDate(2020, invalid, 24), `month ${typeof invalid}`); + assert.throws(RangeError, () => new Temporal.PlainDate(2020, 11, invalid), `day ${typeof invalid}`); +} +const actual = []; +const args = [ + TemporalHelpers.toPrimitiveObserver(actual, 2020, "year"), + TemporalHelpers.toPrimitiveObserver(actual, 11, "month"), + TemporalHelpers.toPrimitiveObserver(actual, 24, "day"), +]; +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(...args), + 2020, 11, "M11", 24, "invalid string"); +assert.compareArray(actual, [ + "get year.valueOf", + "call year.valueOf", + "get month.valueOf", + "call month.valueOf", + "get day.valueOf", + "call day.valueOf", +]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-invalid.js new file mode 100644 index 0000000000..4e1191ee98 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/argument-invalid.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.plaindate +description: PlainDate constructor with invalid iso dates +features: [Temporal] +---*/ + +const tests = [ + [2020, 0, 24], + [2020, 13, 24], + [2020, -3, 24], + [2020, 12, 32], + [2020, 2, 30], + [2019, 2, 29], + [2019, 2, 0], + [2019, 2, -20], +]; + +for (const [year, month, day] of tests) { + assert.throws(RangeError, () => new Temporal.PlainDate(year, month, day), + `year=${year}, month=${month}, day=${day}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/basic.js new file mode 100644 index 0000000000..fab877e5e5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/basic.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.plaindate +description: Basic tests for the PlainDate constructor. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +Object.defineProperty(Temporal.Calendar, "from", { + get() { + throw new Test262Error("Should not get Calendar.from"); + }, +}); + +const calendar = new Temporal.Calendar("iso8601"); +const plainDateWithObject = new Temporal.PlainDate(2020, 12, 24, calendar); +TemporalHelpers.assertPlainDate(plainDateWithObject, 2020, 12, "M12", 24, "with object"); +assert.sameValue(plainDateWithObject.getCalendar(), calendar); + +const plainDateWithString = new Temporal.PlainDate(2020, 12, 24, "iso8601"); +TemporalHelpers.assertPlainDate(plainDateWithString, 2020, 12, "M12", 24, "with string"); +assert.sameValue(plainDateWithString.getISOFields().calendar, "iso8601", "calendar slot should store a string"); +assert.notSameValue(plainDateWithString.getCalendar(), calendar); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/builtin.js new file mode 100644 index 0000000000..bc862877d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Tests that Temporal.PlainDate 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.PlainDate), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate), + Function.prototype, "prototype"); + +assert.sameValue(typeof Temporal.PlainDate.prototype, + "object", "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-case-insensitive.js new file mode 100644 index 0000000000..406dbc44c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Calendar names are case-insensitive +features: [Temporal] +---*/ + +const arg = "iSo8601"; + +const result = new Temporal.PlainDate(2000, 5, 2, arg); +assert.sameValue(result.calendarId, "iso8601", "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-number.js new file mode 100644 index 0000000000..cd0f23b107 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +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.PlainDate(2000, 5, 2, arg), + "A number is not a valid ISO string for Calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-string.js new file mode 100644 index 0000000000..d4be3beed6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.constructor +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const arg = "iso8601"; + +const result = new Temporal.PlainDate(2000, 5, 2, arg); +assert.sameValue(result.getISOFields().calendar, "iso8601", `Calendar created from string "${arg}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-temporal-object.js new file mode 100644 index 0000000000..73f0b2f227 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +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.PlainDate(2000, 5, 2, arg); + 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/PlainDate/calendar-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-undefined.js new file mode 100644 index 0000000000..64d68fd512 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Calendar argument defaults to the built-in ISO 8601 calendar +features: [Temporal] +---*/ + +const args = [2020, 12, 24]; + +Object.defineProperty(Temporal.Calendar, "from", { + get() { + throw new Test262Error("Should not get Calendar.from"); + }, +}); + +const dateExplicit = new Temporal.PlainDate(...args, undefined); +assert.sameValue(dateExplicit.getISOFields().calendar, "iso8601", "calendar slot should store string"); + +const dateImplicit = new Temporal.PlainDate(...args); +assert.sameValue(dateImplicit.getISOFields().calendar, "iso8601", "calendar slot should store string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/calendar-wrong-type.js new file mode 100644 index 0000000000..21897ea402 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +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.PlainDate(2000, 5, 2, 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"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => new Temporal.PlainDate(2000, 5, 2, arg), `${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/PlainDate/compare/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..33567d5266 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, day: 2, calendar: "iso8601" }; +Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)); +Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..08733a161f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-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.plaindate.compare +description: > + Calendar.dateFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const arg1 = { year: 2000, month: 5, day: 2, calendar }; +const arg2 = new Temporal.PlainDate(1976, 11, 18); + +Temporal.PlainDate.compare(arg1, arg2); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar (first argument)"); + +calendar.dateFromFieldsCallCount = 0; + +Temporal.PlainDate.compare(arg2, arg1); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar (first argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..d7f5b98479 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-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.plaindate.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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18))); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..2898cce8e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-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.plaindate.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'], ['day'], ['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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18))); + assert.throws(RangeError, () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-number.js new file mode 100644 index 0000000000..62c0596003 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-number.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.plaindate.compare +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + "A number is not a valid ISO string for PlainDate (first argument)" + ); + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + "A number is not a valid ISO string for PlainDate (second argument)" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-object.js new file mode 100644 index 0000000000..ad96dcbb27 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-object.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.plaindate.compare +description: basic object coercion in arguments +features: [Temporal] +---*/ + +const d1 = Temporal.PlainDate.from("1976-11-18"); +const d2 = Temporal.PlainDate.from("2019-06-30"); + +assert.sameValue(Temporal.PlainDate.compare({ year: 1976, month: 11, day: 18 }, d2), -1, "first argument"); +assert.sameValue(Temporal.PlainDate.compare({ year: 2019, month: 6, day: 30 }, d2), 0, "first argument"); +assert.sameValue(Temporal.PlainDate.compare({ year: 2024, month: 1, day: 12 }, d2), 1, "first argument"); + +assert.sameValue(Temporal.PlainDate.compare(d1, { year: 2024, month: 1, day: 12 }), -1, "second argument"); +assert.sameValue(Temporal.PlainDate.compare(d1, { year: 1976, month: 11, day: 18 }), 0, "second argument"); +assert.sameValue(Temporal.PlainDate.compare(d1, { year: 1926, month: 7, day: 7 }), 1, "second argument"); + +assert.throws(TypeError, () => Temporal.PlainDate.compare({ year: 1976 }, d2), "only year in first argument"); +assert.throws(TypeError, () => Temporal.PlainDate.compare(d1, { year: 2019 }), "only year in second argument"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-plaindatetime.js new file mode 100644 index 0000000000..5666cdb980 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-plaindatetime.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.plaindate.compare +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindate.compare steps 1–2: + 1. Set _one_ to ? ToTemporalDate(_one_). + 2. Set _two_ to ? ToTemporalDate(_two_). + sec-temporal-totemporaldate step 2.b: + b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then + i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const sameDate = new Temporal.PlainDate(2000, 5, 2); +const earlierDate = new Temporal.PlainDate(1920, 7, 3); +const laterDate = new Temporal.PlainDate(2005, 1, 12); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(datetime, sameDate); + assert.sameValue(result, 0, "First argument, same date: comparison result"); +}, "First argument, same date"); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(datetime, earlierDate); + assert.sameValue(result, 1, "First argument, earlier date: comparison result"); +}, "First argument, earlier date"); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(datetime, laterDate); + assert.sameValue(result, -1, "First argument, later date: comparison result"); +}, "First argument, later date"); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(sameDate, datetime); + assert.sameValue(result, 0, "Second argument, same date: comparison result"); +}, "Second argument, same date"); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(earlierDate, datetime); + assert.sameValue(result, -1, "Second argument, earlier date: comparison result"); +}, "Second argument, earlier date"); + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const result = Temporal.PlainDate.compare(laterDate, datetime); + assert.sameValue(result, 1, "Second argument, later date: comparison result"); +}, "Second argument, later date"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..531868629a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result1 = Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)); +assert.sameValue(result1, 0, "Calendar is case-insensitive (first argument)"); +const result2 = Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg); +assert.sameValue(result2, 0, "Calendar is case-insensitive (second argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..34e69918a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-leap-second.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.plaindate.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: 1976, monthCode: "M11", day: 18, calendar }; +const result1 = Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)); +assert.sameValue(result1, 0, "leap second is a valid ISO string for calendar (first argument)"); +const result2 = Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg); +assert.sameValue(result2, 0, "leap second is a valid ISO string for calendar (first argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..076c5088cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, calendar }; + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + "A number is not a valid ISO string for calendar (first argument)" + ); + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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/PlainDate/compare/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..3c47b5e003 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, calendar }; + +const result1 = Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)); +assert.sameValue(result1, 0, `Calendar created from string "${arg}" (first argument)`); + +const result2 = Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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/PlainDate/compare/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..a347aeee90 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `${description} does not convert to a valid ISO string (first argument)` + ); + assert.throws( + typeof calendar === "string" ? RangeError : TypeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), `${description} is not a valid property bag and does not convert to a string (first argument)`); + assert.throws(TypeError, () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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/PlainDate/compare/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..4bee8a16e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + "reject minus zero as extended year (first argument)" + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + "reject minus zero as extended year (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..70463984e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-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.plaindate.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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18))); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..67725aae57 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/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.plaindate.compare +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02[u-ca=iso8601]", "without time or time zone"], + ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"], + ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"], + ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.compare(arg, arg); + + assert.sameValue( + result, + 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..375258ee4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-critical-unknown-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.plaindate.compare +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[!foo=bar]", + "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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `reject unknown annotation with critical flag: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + `reject unknown annotation with critical flag: ${arg} (second argument)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..a2d429d48f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-date-with-utc-offset.js @@ -0,0 +1,51 @@ +// |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.plaindate.compare +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const validStrings = [ + "2000-05-02T00+00:00", + "2000-05-02T00+00:00[UTC]", + "2000-05-02T00+00:00[!UTC]", + "2000-05-02T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = Temporal.PlainDate.compare(arg, arg); + + assert.sameValue( + result, + 0, + `"${arg}" is a valid UTC offset with time for PlainDate` + ); +} + +const invalidStrings = [ + "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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `"${arg}" UTC offset without time is not valid for PlainDate (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + `"${arg}" UTC offset without time is not valid for PlainDate (second argument)` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js new file mode 100644 index 0000000000..7e50608f49 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |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.plaindate.compare +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const other = new Temporal.PlainDate(2020, 1, 1); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(arg, other), + `"${arg}" should not be a valid ISO string for a PlainDate (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(other, arg), + `"${arg}" should not be a valid ISO string for a PlainDate (second argument)` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..816af9c8cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `reject more than one calendar annotation if any critical: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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/PlainDate/compare/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..ea7794faf2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-multiple-time-zone.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.plaindate.compare +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[UTC][UTC]", + "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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `reject more than one time zone annotation: ${arg} (first argument)` + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + `reject more than one time zone annotation: ${arg} (second argument)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-time-separators.js new file mode 100644 index 0000000000..7d3a055703 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const tests = [ + ["2000-05-02T15:23", "uppercase T"], + ["2000-05-02t15:23", "lowercase T"], + ["2000-05-02 15:23", "space between date and time"], +]; + +tests.forEach(([arg, description]) => { + assert.sameValue( + Temporal.PlainDate.compare(arg, date), + 0, + `variant time separators (${description}), first argument` + ); + + assert.sameValue( + Temporal.PlainDate.compare(date, arg), + 0, + `variant time separators (${description}), second argument` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..a7cd502511 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-time-zone-annotation.js @@ -0,0 +1,36 @@ +// |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.plaindate.compare +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ['2000-05-02[Asia/Kolkata]', 'named, with no time'], + ['2000-05-02[!Europe/Vienna]', 'named, with ! and no time'], + ['2000-05-02[+00:00]', 'numeric, with no time'], + ['2000-05-02[!-02:30]', 'numeric, with ! and no time'], + ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"], + ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"], + ["2000-05-02T15:23[-02:30]", "numeric, with no offset"], + ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"], + ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"], + ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"], + ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"], + ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.compare(arg, arg); + + assert.sameValue( + result, + 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..869ac1e464 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/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.plaindate.compare +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02[foo=bar]", "without time"], + ["2000-05-02T15:23[foo=bar]", "alone"], + ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"], + ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.compare(arg, arg); + + assert.sameValue( + result, + 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..d434dbc6a6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: RangeError thrown if a string with UTC designator is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const plainDate = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(arg, plainDate), + "String with UTC designator should not be valid as a PlainDate (first argument)" + ); + assert.throws( + RangeError, + () => Temporal.PlainDate.compare(plainDate, arg), + "String with UTC designator should not be valid as a PlainDate (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string.js new file mode 100644 index 0000000000..cb7969a861 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-string.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.plaindate.compare +description: basic string coercion in arguments +features: [Temporal] +---*/ + +const d1 = Temporal.PlainDate.from("1976-11-18"); +const d2 = Temporal.PlainDate.from("2019-06-30"); + +assert.sameValue(Temporal.PlainDate.compare("1976-11-18", d2), -1, "first argument"); +assert.sameValue(Temporal.PlainDate.compare("2019-06-30", d2), 0, "first argument"); +assert.sameValue(Temporal.PlainDate.compare("2024-01-12", d2), 1, "first argument"); + +assert.sameValue(Temporal.PlainDate.compare(d1, "2019-06-30"), -1, "second argument"); +assert.sameValue(Temporal.PlainDate.compare(d1, "1976-11-18"), 0, "second argument"); +assert.sameValue(Temporal.PlainDate.compare(d1, "1926-07-07"), 1, "second argument"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-wrong-type.js new file mode 100644 index 0000000000..29d8f2ba6a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDate +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.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), + `${description} does not convert to a valid ISO string (first argument)` + ); + assert.throws( + typeof arg === 'string' ? RangeError : TypeError, + () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg), + `${description} does not convert to a valid ISO string (second argument)` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainDate, "Temporal.PlainDate, object"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)), `${description} is not a valid property bag and does not convert to a string (first argument)`); + assert.throws(TypeError, () => Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), 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/PlainDate/compare/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..deb5803a86 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-slots.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.plaindate.compare +description: Getters are not called when converting a ZonedDateTime to a PlainDate. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype); +const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"]; + +for (const property of getters) { + Object.defineProperty(Temporal.ZonedDateTime.prototype, property, { + get() { + actual.push(`get ${property}`); + const value = prototypeDescrs[property].get.call(this); + return { + toString() { + actual.push(`toString ${property}`); + return value.toString(); + }, + valueOf() { + actual.push(`valueOf ${property}`); + return value; + }, + }; + }, + }); +} + +const arg = new Temporal.ZonedDateTime(0n, "UTC"); +Temporal.PlainDate.compare(arg, new Temporal.PlainDate(1976, 11, 18)); +Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..7dcdaf5d6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.compare +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, Infinity, -Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const date = new Temporal.PlainDate(2000, 5, 2); + + assert.throws(RangeError, () => Temporal.PlainDate.compare(datetime, date)); + assert.throws(RangeError, () => Temporal.PlainDate.compare(date, datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..2ecaa0ad9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.compare +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const date = new Temporal.PlainDate(2000, 5, 2); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(datetime, date), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); + assert.throws( + TypeError, + () => Temporal.PlainDate.compare(date, datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..45bb1081c6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.compare +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_001, 86400_000_000_001].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const date = new Temporal.PlainDate(2000, 5, 2); + + assert.throws(RangeError, () => Temporal.PlainDate.compare(datetime, date)); + assert.throws(RangeError, () => Temporal.PlainDate.compare(date, datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..669a216d5b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.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.plaindate.compare +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const date = new Temporal.PlainDate(2000, 5, 2); + + assert.throws(TypeError, () => Temporal.PlainDate.compare(datetime, date)); + assert.throws(TypeError, () => Temporal.PlainDate.compare(date, datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime.js new file mode 100644 index 0000000000..a6654b357b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/argument-zoneddatetime.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.plaindate.compare +description: ZonedDateTime is supported. +features: [Temporal] +---*/ + +const zdt = new Temporal.ZonedDateTime(0n, "UTC"); +assert.sameValue( + Temporal.PlainDate.compare(zdt, new Temporal.PlainDate(1970, 1, 1)), + 0, "same date, ZDT first"); +assert.sameValue( + Temporal.PlainDate.compare(new Temporal.PlainDate(1970, 1, 1), zdt), + 0, "same date, ZDT second"); +assert.sameValue( + Temporal.PlainDate.compare(zdt, new Temporal.PlainDate(1976, 11, 18)), + -1, "different date, ZDT first"); +assert.sameValue( + Temporal.PlainDate.compare(new Temporal.PlainDate(1976, 11, 18), zdt), + 1, "different date, ZDT second"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/basic.js new file mode 100644 index 0000000000..ffb86010e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/basic.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.plaindate.compare +description: basic tests +features: [Temporal] +---*/ + +const d1 = Temporal.PlainDate.from("1976-11-18"); +const d2 = Temporal.PlainDate.from("2019-06-30"); +const d3 = Temporal.PlainDate.from("2019-06-30"); +assert.sameValue(Temporal.PlainDate.compare(d1, d1), 0, "same object"); +assert.sameValue(Temporal.PlainDate.compare(d1, d2), -1, "earlier"); +assert.sameValue(Temporal.PlainDate.compare(d2, d1), 1, "later"); +assert.sameValue(Temporal.PlainDate.compare(d2, d3), 0, "same date"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/builtin.js new file mode 100644 index 0000000000..943c3e4c9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Tests that Temporal.PlainDate.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.PlainDate.compare), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.compare), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.compare), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.compare.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..4884cd37a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-datefromfields-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.plaindate.prototype.compare +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +Temporal.PlainDate.compare({ year: 2000, month: 5, day: 2, calendar }, { year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-fields-iterable.js new file mode 100644 index 0000000000..08ec8dd712 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-fields-iterable.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.plaindate.compare +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.compare steps 1–2: + 1. Set _one_ to ? ToTemporalDate(_one_). + 2. Set _two_ to ? ToTemporalDate(_two_). + sec-temporal-totemporaldate 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +Temporal.PlainDate.compare( + { year: 2000, month: 5, day: 2, calendar: calendar1 }, + { year: 2001, month: 6, day: 3, 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/PlainDate/compare/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar-temporal-object.js new file mode 100644 index 0000000000..e7f8b6216a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindate.compare steps 1–2: + 1. Set _one_ to ? ToTemporalDate(_one_). + 2. Set _two_ to ? ToTemporalDate(_two_). + sec-temporal-totemporaldate step 2.c: + c. 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.PlainDate.compare( + { year: 2000, month: 5, day: 2, calendar: temporalObject }, + { year: 2001, month: 6, day: 3, calendar: temporalObject }, + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar.js new file mode 100644 index 0000000000..6089850753 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/calendar.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.plaindate.compare +description: basic tests +features: [Temporal] +---*/ + +class CalendarTraceToString extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this.id_ = id; + this.calls = 0; + } + toString() { + ++this.calls; + return this.id_; + } +}; + +const calendar1 = new CalendarTraceToString("a"); +const date1 = new Temporal.PlainDate(1914, 2, 23, calendar1); + +const calendar2 = new CalendarTraceToString("a"); +const date2 = new Temporal.PlainDate(1914, 2, 23, calendar2); + +const calendar3 = new CalendarTraceToString("b"); +const date3 = new Temporal.PlainDate(1914, 2, 23, calendar3); + +assert.sameValue(Temporal.PlainDate.compare(date1, date1), 0, "same object"); +assert.sameValue(Temporal.PlainDate.compare(date1, date2), 0, "same date"); +assert.sameValue(Temporal.PlainDate.compare(date1, date3), 0, "same date, different calendar"); + +assert.sameValue(calendar1.calls, 0, "calendar1 toString() calls"); +assert.sameValue(calendar2.calls, 0, "calendar2 toString() calls"); +assert.sameValue(calendar3.calls, 0, "calendar3 toString() calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/exhaustive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/exhaustive.js new file mode 100644 index 0000000000..9858787bcb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/exhaustive.js @@ -0,0 +1,71 @@ +// |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.plaindate.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.PlainDate.compare( + new Temporal.PlainDate(2000, 5, 31, cal1), + new Temporal.PlainDate(1987, 5, 31, cal2) + ), + 1, + "year >" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(1981, 12, 15, cal1), + new Temporal.PlainDate(2048, 12, 15, cal2) + ), + -1, + "year <" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(2000, 5, 31, cal1), + new Temporal.PlainDate(2000, 3, 31, cal2) + ), + 1, + "month >" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(1981, 4, 15, cal1), + new Temporal.PlainDate(1981, 12, 15, cal2) + ), + -1, + "month <" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(2000, 5, 31, cal1), + new Temporal.PlainDate(2000, 5, 14, cal2) + ), + 1, + "day >" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(1981, 4, 15, cal1), + new Temporal.PlainDate(1981, 4, 21, cal2) + ), + -1, + "day <" +); +assert.sameValue( + Temporal.PlainDate.compare( + new Temporal.PlainDate(2000, 5, 31, cal1), + new Temporal.PlainDate(2000, 5, 31, cal2) + ), + 0, + "=" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..0f62ef3be2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const other = new Temporal.PlainDate(2000, 5, 2); +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].forEach((prop) => { + assert.throws(RangeError, () => Temporal.PlainDate.compare({ ...base, [prop]: inf }, other), `${prop} property cannot be ${inf}`); + + assert.throws(RangeError, () => Temporal.PlainDate.compare(other, { ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls1 = []; + const obj1 = TemporalHelpers.toPrimitiveObserver(calls1, inf, prop); + assert.throws(RangeError, () => Temporal.PlainDate.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.PlainDate.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/PlainDate/compare/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/leap-second.js new file mode 100644 index 0000000000..a815452419 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/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.plaindate.compare +description: Leap second is a valid ISO string for PlainDate +features: [Temporal] +---*/ + +let arg = "2016-12-31T23:59:60"; +let result = Temporal.PlainDate.compare(arg, new Temporal.PlainDate(2016, 12, 31)); +assert.sameValue(result, 0, "leap second is a valid ISO string for PlainDate (first argument)"); +result = Temporal.PlainDate.compare(new Temporal.PlainDate(2016, 12, 31), arg); +assert.sameValue(result, 0, "leap second is a valid ISO string for PlainDate (second argument)"); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +result = Temporal.PlainDate.compare(arg, new Temporal.PlainDate(2016, 12, 31)); +assert.sameValue(result, 0, "second: 60 is ignored in property bag for PlainDate (first argument)"); +result = Temporal.PlainDate.compare(new Temporal.PlainDate(2016, 12, 31), arg); +assert.sameValue(result, 0, "second: 60 is ignored in property bag for PlainDate (second argument)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/length.js new file mode 100644 index 0000000000..97245bc5b9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Temporal.PlainDate.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.PlainDate.compare, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/name.js new file mode 100644 index 0000000000..ea93f5cc06 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Temporal.PlainDate.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.PlainDate.compare, "name", { + value: "compare", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/not-a-constructor.js new file mode 100644 index 0000000000..d7ee33d50d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: Temporal.PlainDate.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.PlainDate.compare(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.compare), false, + "isConstructor(Temporal.PlainDate.compare)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/prop-desc.js new file mode 100644 index 0000000000..39f85f1760 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.compare +description: The "compare" property of Temporal.PlainDate +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.compare, + "function", + "`typeof PlainDate.compare` is `function`" +); + +verifyProperty(Temporal.PlainDate, "compare", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/compare/use-internal-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/use-internal-slots.js new file mode 100644 index 0000000000..2f8a0c4a2a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/use-internal-slots.js @@ -0,0 +1,29 @@ +// |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-compareisodate +description: compare() ignores the observable properties and uses internal slots +features: [Temporal] +---*/ + +function CustomError() {} + +class AvoidGettersDate extends Temporal.PlainDate { + get year() { + throw new CustomError(); + } + get month() { + throw new CustomError(); + } + get day() { + throw new CustomError(); + } +} + +const one = new AvoidGettersDate(2000, 5, 2); +const two = new AvoidGettersDate(2006, 3, 25); +assert.sameValue(Temporal.PlainDate.compare(one, two), -1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/year-zero.js new file mode 100644 index 0000000000..4af85b15ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/compare/year-zero.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. + +/*--- +description: Negative zero, as an extended year, fails +esid: sec-temporal.plaindate.compare +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T00:45", + "-000000-10-31T00:45+01:00", + "-000000-10-31T00:45+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws(RangeError, + () => Temporal.PlainDate.compare(arg, instance), + "Minus zero is an invalid extended year (first argument)" + ); + + assert.throws(RangeError, + () => Temporal.PlainDate.compare(instance, arg), + "Minus zero is an invalid extended year (second argument)" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/constructor.js new file mode 100644 index 0000000000..091305f0e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Temporal.PlainDate constructor cannot be called as a function +info: | + 1. If NewTarget is undefined, throw a TypeError exception. +features: [Temporal] +---*/ + +assert.throws(TypeError, () => Temporal.PlainDate(1970, 1, 2)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..4bc627ff84 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, day: 2, calendar: "iso8601" }; +Temporal.PlainDate.from(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..0a72943f56 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-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.plaindate.from +description: > + Calendar.dateFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const arg = { year: 2000, month: 5, day: 2, calendar }; +Temporal.PlainDate.from(arg); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..a3e0d96bf8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-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.plaindate.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.PlainDate.from(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..bf3482afba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-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.plaindate.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'], ['day'], ['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.PlainDate.from(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-leap-second.js new file mode 100644 index 0000000000..c3436f7d6b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-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.plaindate.from +description: Leap second is a valid ISO string for PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let arg = "2016-12-31T23:59:60"; + +const result1 = Temporal.PlainDate.from(arg); +TemporalHelpers.assertPlainDate( + result1, + 2016, 12, "M12", 31, + "leap second is a valid ISO string for PlainDate" +); + +const result2 = Temporal.PlainDate.from(arg, { overflow: "reject" }); +TemporalHelpers.assertPlainDate( + result2, + 2016, 12, "M12", 31, + "leap second is a valid ISO string for PlainDate" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; + +const result3 = Temporal.PlainDate.from(arg); +TemporalHelpers.assertPlainDate( + result3, + 2016, 12, "M12", 31, + "second: 60 is ignored in property bag for PlainDate" +); + +const result4 = Temporal.PlainDate.from(arg, { overflow: "reject" }); +TemporalHelpers.assertPlainDate( + result4, + 2016, 12, "M12", 31, + "second: 60 is ignored in property bag for PlainDate even with overflow: reject" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-number.js new file mode 100644 index 0000000000..492564b840 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => Temporal.PlainDate.from(arg), + 'Numbers cannot be used in place of an ISO string for PlainDate' + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-invalid.js new file mode 100644 index 0000000000..5c683bcff3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-invalid.js @@ -0,0 +1,44 @@ +// |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.plaindate.from +description: Property bag is correctly converted into PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const badFields = { year: 2019, month: 1, day: 32 }; +assert.throws(RangeError, () => Temporal.PlainDate.from(badFields, { overflow: "reject" }), + "bad fields with reject"); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from(badFields), + 2019, 1, "M01", 31, "bad fields with missing overflow"); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from(badFields, { overflow: "constrain" }), + 2019, 1, "M01", 31, "bad fields with constrain"); + +assert.throws(RangeError, + () => Temporal.PlainDate.from({ year: 1976, month: 11, monthCode: "M12", day: 18 }), + "month and monthCode must agree"); + +assert.throws(TypeError, + () => Temporal.PlainDate.from({ year: 2019, day: 15 }), + "missing month"); + +assert.throws(TypeError, + () => Temporal.PlainDate.from({}), + "no properties"); + +assert.throws(TypeError, + () => Temporal.PlainDate.from({ month: 12 }), + "missing year, day"); + +assert.throws(TypeError, + () => Temporal.PlainDate.from({ year: 1976, months: 11, day: 18 }), + "misspelled month"); + +assert.throws(TypeError, + () => Temporal.PlainDate.from({ year: undefined, month: 11, day: 18 }), + "year undefined"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-valid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-valid.js new file mode 100644 index 0000000000..c02ee292b4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-object-valid.js @@ -0,0 +1,36 @@ +// |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.plaindate.from +description: Property bag is correctly converted into PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const valid = [ + [ + { year: 2019, month: 10, monthCode: "M10", day: 1, hour: 14, minute: 20, second: 36 }, + 2019, 10, "M10", 1 + ], + [ + { year: 1976, month: 11, day: 18 }, + 1976, 11, "M11", 18 + ], + [ + { year: 1976, monthCode: "M11", day: 18 }, + 1976, 11, "M11", 18 + ], + [ + { year: 1976, month: 11, day: 18, days: 15 }, + 1976, 11, "M11", 18 + ], +]; + +for (const [dateTimeFields, ...expected] of valid) { + const plainDate = Temporal.PlainDate.from(dateTimeFields); + TemporalHelpers.assertPlainDate(plainDate, ...expected, `from(${JSON.stringify(dateTimeFields)}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindate.js new file mode 100644 index 0000000000..38c381790e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindate.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.plaindate.from +description: A PlainDate object is copied, not returned directly +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const orig = new Temporal.PlainDate(2000, 5, 2); +const result = Temporal.PlainDate.from(orig); + +TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + "PlainDate is copied" +); + +assert.sameValue(result.getISOFields().calendar, orig.getISOFields().calendar, "Calendar is copied"); + +assert.notSameValue( + result, + orig, + "When a PlainDate is given, the returned value is not the original PlainDate" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindatetime.js new file mode 100644 index 0000000000..a98ce76168 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-plaindatetime.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.plaindate.from +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindate.from step 3: + 3. Return ? ToTemporalDate(_item_, _options_). + sec-temporal-totemporaldate step 2.b: + b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then + i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime, calendar) => { + const result = Temporal.PlainDate.from(datetime); + TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 2); + assert.sameValue(result.getCalendar(), calendar, "calendar result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..877c77b77b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = Temporal.PlainDate.from(arg); +TemporalHelpers.assertPlainDate(result, 1976, 11, "M11", 18, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..21fea60629 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, calendar }; +const result = Temporal.PlainDate.from(arg); +TemporalHelpers.assertPlainDate( + result, + 1976, 11, "M11", 18, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..f33a84fb5e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, calendar }; + assert.throws( + TypeError, + () => Temporal.PlainDate.from(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..405ef9d022 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = Temporal.PlainDate.from(arg); +TemporalHelpers.assertPlainDate(result, 1976, 11, "M11", 18, `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/PlainDate/from/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..0fc09911a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.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.PlainDate.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/PlainDate/from/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..fc65d8fd12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.from(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar.js new file mode 100644 index 0000000000..8c9ae4c2a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-propertybag-calendar.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.plaindate.from +description: Property bag is correctly converted into PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const plainDate = Temporal.PlainDate.from({ year: 1976, month: 11, day: 18, calendar }); +TemporalHelpers.assertPlainDate(plainDate, 1976, 11, "M11", 18); +assert.sameValue(plainDate.getISOFields().calendar, "iso8601", "calendar slot should store a string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..19253021b2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-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.plaindate.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.PlainDate.from(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..d7d6696d2f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/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.plaindate.from +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[u-ca=iso8601]", "without time or time zone"], + ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"], + ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"], + ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.from(arg); + + TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..b1ac214b95 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-critical-unknown-annotation.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.plaindate.from +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[!foo=bar]", + "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.PlainDate.from(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..14cba00fe5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-date-with-utc-offset.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.plaindate.from +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const validStrings = [ + "2000-05-02T00+00:00", + "2000-05-02T00+00:00[UTC]", + "2000-05-02T00+00:00[!UTC]", + "2000-05-02T00-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = Temporal.PlainDate.from(arg); + + TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + `"${arg}" is a valid UTC offset with time for PlainDate` + ); +} + +const invalidStrings = [ + "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.PlainDate.from(arg), + `"${arg}" UTC offset without time is not valid for PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-invalid.js new file mode 100644 index 0000000000..d8cd182a20 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-invalid.js @@ -0,0 +1,63 @@ +// |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.plaindate.from +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..a305783053 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate.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/PlainDate/from/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..13fd43cbcb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-multiple-time-zone.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.plaindate.from +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[UTC][UTC]", + "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.PlainDate.from(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-time-separators.js new file mode 100644 index 0000000000..6333981784 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02T15:23", "uppercase T"], + ["2000-05-02t15:23", "lowercase T"], + ["2000-05-02 15:23", "space between date and time"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.from(arg); + + TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..6593865f70 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-time-zone-annotation.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.plaindate.from +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[Asia/Kolkata]", "named, with no time"], + ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"], + ["2000-05-02[+00:00]", "numeric, with no time"], + ["2000-05-02[!-02:30]", "numeric, with ! and no time"], + ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"], + ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"], + ["2000-05-02T15:23[-02:30]", "numeric, with no offset"], + ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"], + ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"], + ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"], + ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"], + ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.from(arg); + + TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-trailing-junk.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-trailing-junk.js new file mode 100644 index 0000000000..d14560a938 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-trailing-junk.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.plaindate.from +description: RangeError thrown if a string with trailing junk is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +assert.throws(RangeError, () => Temporal.PlainDate.from("1976-11-18junk"), + "String with trailing junk should not be valid as a PlainDate"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..ff0eb36df6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/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.plaindate.from +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[foo=bar]", "without time"], + ["2000-05-02T15:23[foo=bar]", "alone"], + ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"], + ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +tests.forEach(([arg, description]) => { + const result = Temporal.PlainDate.from(arg); + + TemporalHelpers.assertPlainDate( + result, + 2000, 5, "M05", 2, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..bdcf201bc4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: RangeError thrown if a string with UTC designator is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(arg), + "String with UTC designator should not be valid as a PlainDate" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string.js new file mode 100644 index 0000000000..c56d47ca2c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-string.js @@ -0,0 +1,42 @@ +// |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.plaindate.from +description: various interesting string arguments. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18", 1976, 11, "M11", 18], + ["2019-06-30", 2019, 6, "M06", 30], + ["+000050-06-30", 50, 6, "M06", 30], + ["+010583-06-30", 10583, 6, "M06", 30], + ["-010583-06-30", -10583, 6, "M06", 30], + ["-000333-06-30", -333, 6, "M06", 30], + ["19761118", 1976, 11, "M11", 18], + ["+0019761118", 1976, 11, "M11", 18], + ["1976-11-18T152330.1+00:00", 1976, 11, "M11", 18], + ["19761118T15:23:30.1+00:00", 1976, 11, "M11", 18], + ["1976-11-18T15:23:30.1+0000", 1976, 11, "M11", 18], + ["1976-11-18T152330.1+0000", 1976, 11, "M11", 18], + ["19761118T15:23:30.1+0000", 1976, 11, "M11", 18], + ["19761118T152330.1+00:00", 1976, 11, "M11", 18], + ["19761118T152330.1+0000", 1976, 11, "M11", 18], + ["+001976-11-18T152330.1+00:00", 1976, 11, "M11", 18], + ["+0019761118T15:23:30.1+00:00", 1976, 11, "M11", 18], + ["+001976-11-18T15:23:30.1+0000", 1976, 11, "M11", 18], + ["+001976-11-18T152330.1+0000", 1976, 11, "M11", 18], + ["+0019761118T15:23:30.1+0000", 1976, 11, "M11", 18], + ["+0019761118T152330.1+00:00", 1976, 11, "M11", 18], + ["+0019761118T152330.1+0000", 1976, 11, "M11", 18], +]; + +for (const [input, ...expected] of tests) { + const result = Temporal.PlainDate.from(input); + TemporalHelpers.assertPlainDate(result, ...expected, `from(${input})`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-wrong-type.js new file mode 100644 index 0000000000..8f7cf439c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDate +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.PlainDate.from(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainDate, "Temporal.PlainDate, object"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => Temporal.PlainDate.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/PlainDate/from/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-convert.js new file mode 100644 index 0000000000..0134e8ab9a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-convert.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.plaindate.from +description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated. +features: [Temporal] +---*/ + +class TZ extends Temporal.TimeZone { + constructor() { super("UTC") } + getOffsetNanosecondsFor() { throw new Test262Error() } +} + +const tz = new TZ(); +const arg = new Temporal.ZonedDateTime(0n, tz); +const instance = new Temporal.PlainDate(1976, 11, 18); + +assert.throws(Test262Error, () => Temporal.PlainDate.from(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..31e2dea78c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-slots.js @@ -0,0 +1,39 @@ +// |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.plaindate.from +description: Getters are not called when converting a ZonedDateTime to a PlainDate. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype); +const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"]; + +for (const property of getters) { + Object.defineProperty(Temporal.ZonedDateTime.prototype, property, { + get() { + actual.push(`get ${property}`); + const value = prototypeDescrs[property].get.call(this); + return { + toString() { + actual.push(`toString ${property}`); + return value.toString(); + }, + valueOf() { + actual.push(`valueOf ${property}`); + return value; + }, + }; + }, + }); +} + +const arg = new Temporal.ZonedDateTime(0n, "UTC"); +Temporal.PlainDate.from(arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..7b4c3b2721 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.from +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => Temporal.PlainDate.from(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..f8c5a7164c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.from +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach(notCallable => { + const timeZone = new Temporal.TimeZone("UTC"); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => Temporal.PlainDate.from(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..775095b425 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.from +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_001, 86400_000_000_001, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => Temporal.PlainDate.from(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..cca5f38eb7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.from +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => Temporal.PlainDate.from(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime.js new file mode 100644 index 0000000000..1601aa288a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/argument-zoneddatetime.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.plaindate.from +description: A ZonedDateTime object is handled separately +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const zdt = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC", calendar); +const result = Temporal.PlainDate.from(zdt); + +TemporalHelpers.assertPlainDate( + result, + 2001, 9, "M09", 9, + "ZonedDateTime is converted" +); + +assert.sameValue( + result.getCalendar(), + calendar, + "Calendar is copied" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/builtin.js new file mode 100644 index 0000000000..2658a4878b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Tests that Temporal.PlainDate.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.PlainDate.from), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.from), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.from), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.from.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-custom.js new file mode 100644 index 0000000000..8c14dc3d6b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-custom.js @@ -0,0 +1,38 @@ +// |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.plaindate.from +description: Verify the result of calendar.fields() is treated correctly. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateFromFields(fields) { + assert.compareArray(Object.keys(fields), ["a", "b"]); + return new Temporal.PlainDate(2020, 7, 4); + } + fields(fields) { + assert.compareArray(fields, ["day", "month", "monthCode", "year"]); + return ["b", "a"]; + } +} + +const calendar = new CustomCalendar(); +const actual = []; +const item = TemporalHelpers.propertyBagObserver(actual, { calendar }, "item"); + +const plainDate = Temporal.PlainDate.from(item); +TemporalHelpers.assertPlainDate(plainDate, 2020, 7, "M07", 4); +assert.compareArray(actual, [ + "get item.calendar", + "get item.a", + "get item.b", +]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-iterable.js new file mode 100644 index 0000000000..3fc52b4530 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-fields-iterable.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.plaindate.from +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.from step 3: + 3. Return ? ToTemporalDate(_item_, _options_). + sec-temporal-totemporaldate 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +Temporal.PlainDate.from({ year: 2000, month: 5, day: 2, 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/PlainDate/from/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/calendar-temporal-object.js new file mode 100644 index 0000000000..9d488d4eb1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindate.from step 3: + 3. Return ? ToTemporalDate(_item_, _options_). + sec-temporal-totemporaldate step 2.c: + c. 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.PlainDate.from({ year: 2000, month: 5, day: 2, 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/PlainDate/from/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..67480076c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].forEach((prop) => { + ["constrain", "reject"].forEach((overflow) => { + assert.throws(RangeError, () => Temporal.PlainDate.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.PlainDate.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/PlainDate/from/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/length.js new file mode 100644 index 0000000000..f6c885ad4d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Temporal.PlainDate.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.PlainDate.from, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/limits.js new file mode 100644 index 0000000000..0d223c582f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/limits.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.plaindate.from +description: PlainDate.from enforces the supported range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const tooEarly = { year: -271821, month: 4, day: 18 }; +const tooLate = { year: 275760, month: 9, day: 14 }; +["reject", "constrain"].forEach((overflow) => { + [tooEarly, tooLate, "-271821-04-18", "+275760-09-14"].forEach((value) => { + assert.throws(RangeError, () => Temporal.PlainDate.from(value, { overflow }), + `${JSON.stringify(value)} with ${overflow}`); + }); +}); + +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from({ year: -271821, month: 4, day: 19 }), + -271821, 4, "M04", 19, "min object"); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from({ year: 275760, month: 9, day: 13 }), + 275760, 9, "M09", 13, "max object"); + +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from("-271821-04-19"), + -271821, 4, "M04", 19, "min string"); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from("+275760-09-13"), + 275760, 9, "M09", 13, "max string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/name.js new file mode 100644 index 0000000000..c1e782a12a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Temporal.PlainDate.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.PlainDate.from, "name", { + value: "from", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/not-a-constructor.js new file mode 100644 index 0000000000..019313865d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Temporal.PlainDate.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.PlainDate.from(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.from), false, + "isConstructor(Temporal.PlainDate.from)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-primitive.js new file mode 100644 index 0000000000..529b32d6d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-primitive.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.plaindate.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.PlainDate.from("2021-05-17", options); +assert.compareArray(actual, expected, "Successful call"); +TemporalHelpers.assertPlainDate(result, 2021, 5, "M05", 17); + +actual.splice(0); // empty it for the next check +const failureExpected = [ + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", +]; + +assert.throws(TypeError, () => Temporal.PlainDate.from(7, options)); +assert.compareArray(actual, failureExpected, "Failing call"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js new file mode 100644 index 0000000000..7d9308e508 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.from +description: overflow property is extracted with ISO-invalid string argument. +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.PlainDate.from("2020-13-34", options)); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-object.js new file mode 100644 index 0000000000..4a4a89f966 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.from +description: Empty object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.assertPlainDate( + Temporal.PlainDate.from({ year: 1976, month: 11, day: 18 }, {}), 1976, 11, "M11", 18, + "options may be an empty plain object" +); + +TemporalHelpers.assertPlainDate( + Temporal.PlainDate.from({ year: 1976, month: 11, day: 18 }, () => {}), 1976, 11, "M11", 18, + "options may be an empty function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-undefined.js new file mode 100644 index 0000000000..15b317f3ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const fields = { year: 2000, month: 13, day: 2 }; + +const explicit = Temporal.PlainDate.from(fields, undefined); +assert.sameValue(explicit.month, 12, "default overflow is constrain"); + +const implicit = Temporal.PlainDate.from(fields); +assert.sameValue(implicit.month, 12, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/options-wrong-type.js new file mode 100644 index 0000000000..5c5eb1fd63 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +for (const value of badOptions) { + assert.throws(TypeError, () => Temporal.PlainDate.from({ year: 1976, month: 11, day: 18 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/order-of-operations.js new file mode 100644 index 0000000000..513ddcf51f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/order-of-operations.js @@ -0,0 +1,79 @@ +// |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.plaindate.from +description: Properties on an object passed to from() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "ownKeys options", + "getOwnPropertyDescriptor options.overflow", + "get options.overflow", + "getOwnPropertyDescriptor options.extra", + "get options.extra", + "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", + "get fields.calendar.dateFromFields", + "get fields.calendar.fields", + "call fields.calendar.fields", + "get fields.day", + "get fields.day.valueOf", + "call fields.day.valueOf", + "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", + "call fields.calendar.dateFromFields", + // inside Calendar.p.dateFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "fields.calendar"); +const fields = TemporalHelpers.propertyBagObserver(actual, { + year: 1.7, + month: 1.7, + monthCode: "M01", + day: 1.7, + calendar, +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { + overflow: "constrain", + extra: "property", +}, "options"); + +const result = Temporal.PlainDate.from(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-invalid-string.js new file mode 100644 index 0000000000..29655c52be --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-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.plaindate.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-totemporaldate steps 2–3: + 2. If Type(_item_) is Object, then + ... + g. Return ? DateFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalDate]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalDate(_item_, _options_). +features: [Temporal] +---*/ + +const validItems = [ + new Temporal.PlainDate(2000, 5, 2), + new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC"), + new Temporal.PlainDateTime(2000, 5, 2, 12), + { year: 2000, month: 5, day: 2 }, + "2000-05-02", +]; + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const item of validItems) { + for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(item, { overflow }), + `invalid overflow ("${overflow}")` + ); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-undefined.js new file mode 100644 index 0000000000..08b28cb336 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-totemporaldate steps 2–3: + 2. If Type(_item_) is Object, then + ... + g. Return ? DateFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalDate]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalDate(_item_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const validValues = [ + new Temporal.PlainDate(2000, 5, 2), + "2000-05-02", +]; +validValues.forEach((value) => { + const explicit = Temporal.PlainDate.from(value, { overflow: undefined }); + TemporalHelpers.assertPlainDate(explicit, 2000, 5, "M05", 2, "overflow is ignored"); + const implicit = Temporal.PlainDate.from(value, {}); + TemporalHelpers.assertPlainDate(implicit, 2000, 5, "M05", 2, "overflow is ignored"); + const lambda = Temporal.PlainDate.from(value, () => {}); + TemporalHelpers.assertPlainDate(lambda, 2000, 5, "M05", 2, "overflow is ignored"); +}); + +const propertyBag = { year: 2000, month: 13, day: 34 }; +const explicit = Temporal.PlainDate.from(propertyBag, { overflow: undefined }); +TemporalHelpers.assertPlainDate(explicit, 2000, 12, "M12", 31, "default overflow is constrain"); +const implicit = Temporal.PlainDate.from(propertyBag, {}); +TemporalHelpers.assertPlainDate(implicit, 2000, 12, "M12", 31, "default overflow is constrain"); +const lambda = Temporal.PlainDate.from(propertyBag, () => {}); +TemporalHelpers.assertPlainDate(lambda, 2000, 12, "M12", 31, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/overflow-wrong-type.js new file mode 100644 index 0000000000..8774278ffd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-totemporaldate steps 2–3: + 2. If Type(_item_) is Object, then + ... + g. Return ? DateFromFields(_calendar_, _fields_, _options_). + 3. Perform ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.from steps 2–3: + 2. If Type(_item_) is Object and _item_ has an [[InitializedTemporalDate]] internal slot, then + a. Perform ? ToTemporalOverflow(_options_). + b. Return ... + 3. Return ? ToTemporalDate(_item_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const validValues = [ + new Temporal.PlainDate(2000, 5, 2), + { year: 2000, month: 5, day: 2 }, + "2000-05-02", +]; +validValues.forEach((value) => TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => Temporal.PlainDate.from(value, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 2, descr), +)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/prop-desc.js new file mode 100644 index 0000000000..0664d2fe4c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: The "from" property of Temporal.PlainDate +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.from, + "function", + "`typeof PlainDate.from` is `function`" +); + +verifyProperty(Temporal.PlainDate, "from", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/from/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/subclassing-ignored.js new file mode 100644 index 0000000000..637f254848 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.from +description: The receiver is never called when calling from() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnoredStatic( + Temporal.PlainDate, + "from", + ["2000-05-02"], + (result) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 2), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/from/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/year-zero.js new file mode 100644 index 0000000000..6bd3006711 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/from/year-zero.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.plaindate.from +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T00:45", + "-000000-10-31T00:45+01:00", + "-000000-10-31T00:45+00:00[UTC]", +]; + +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => Temporal.PlainDate.from(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..33355c37ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/infinity-throws-rangeerror.js @@ -0,0 +1,42 @@ +// |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.PlainDate throws a RangeError if any value is Infinity +esid: sec-temporal.plaindate +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +assert.throws(RangeError, () => new Temporal.PlainDate(Infinity, 1, 1)); +assert.throws(RangeError, () => new Temporal.PlainDate(1970, Infinity, 1)); +assert.throws(RangeError, () => new Temporal.PlainDate(1970, 1, Infinity)); + +const O = (primitiveValue, propertyName) => (calls) => TemporalHelpers.toPrimitiveObserver(calls, primitiveValue, propertyName); +const tests = [ + [ + "infinite year", + [O(Infinity, "year"), O(1, "month"), O(1, "day")], + ["get year.valueOf", "call year.valueOf"] + ], + [ + "infinite month", + [O(2, "year"), O(Infinity, "month"), O(1, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf"] + ], + [ + "infinite day", + [O(2, "year"), O(1, "month"), 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.PlainDate(...args_), description); + assert.compareArray(actual, expected, `${description} order of operations`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/length.js new file mode 100644 index 0000000000..bd19e68bae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Temporal.PlainDate.length is 3 +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.PlainDate, "length", { + value: 3, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/limits.js new file mode 100644 index 0000000000..10fb6a5e24 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/limits.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.plaindate +description: Limits for the PlainDate constructor. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +assert.throws(RangeError, () => new Temporal.PlainDate(-271821, 4, 18), "min"); +assert.throws(RangeError, () => new Temporal.PlainDate(275760, 9, 14), "max"); +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(-271821, 4, 19), + -271821, 4, "M04", 19, "min"); +TemporalHelpers.assertPlainDate(new Temporal.PlainDate(275760, 9, 13), + 275760, 9, "M09", 13, "max"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/missing-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/missing-arguments.js new file mode 100644 index 0000000000..86a92f87ef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/missing-arguments.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.plaindate +description: RangeError thrown when constructor invoked with no argument +includes: [compareArray.js] +features: [Temporal] +---*/ + +const expected = [ + "valueOf year", + "valueOf month", +]; +const actual = []; +const args = [ + { valueOf() { actual.push("valueOf year"); return 1; } }, + { valueOf() { actual.push("valueOf month"); return 1; } }, +]; + +assert.throws(RangeError, () => new Temporal.PlainDate(...args)); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/name.js new file mode 100644 index 0000000000..f5d4ba06ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Temporal.PlainDate.name is "PlainDate" +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.PlainDate, "name", { + value: "PlainDate", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..159ce4b9ed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/negative-infinity-throws-rangeerror.js @@ -0,0 +1,42 @@ +// |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.PlainDate throws a RangeError if any value is -Infinity +esid: sec-temporal.plaindate +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +assert.throws(RangeError, () => new Temporal.PlainDate(-Infinity, 1, 1)); +assert.throws(RangeError, () => new Temporal.PlainDate(1970, -Infinity, 1)); +assert.throws(RangeError, () => new Temporal.PlainDate(1970, 1, -Infinity)); + +const O = (primitiveValue, propertyName) => (calls) => TemporalHelpers.toPrimitiveObserver(calls, primitiveValue, propertyName); +const tests = [ + [ + "infinite year", + [O(-Infinity, "year"), O(1, "month"), O(1, "day")], + ["get year.valueOf", "call year.valueOf"] + ], + [ + "infinite month", + [O(2, "year"), O(-Infinity, "month"), O(1, "day")], + ["get year.valueOf", "call year.valueOf", "get month.valueOf", "call month.valueOf"] + ], + [ + "infinite day", + [O(2, "year"), O(1, "month"), 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.PlainDate(...args_), description); + assert.compareArray(actual, expected, `${description} order of operations`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prop-desc.js new file mode 100644 index 0000000000..b8c8daf832 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: The "PlainDate" property of Temporal +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate, + "function", + "`typeof PlainDate` is `function`" +); + +verifyProperty(Temporal, "PlainDate", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-duration-max.js new file mode 100644 index 0000000000..22e0436354 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1970, 1, 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.assertPlainDate(result, 275760, 9, "M09", 13, `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"], + ["-P14285714W3DT23H59M59.999999999S", "string with min weeks"], + [{ weeks: -14285714, days: -3, nanoseconds: -86399999999999 }, "property bag with min weeks"], + ["-P100000001DT23H59M59.999999999S", "string with min days"], + [{ days: -100000001, nanoseconds: -86399999999999 }, "property bag with min days"], + ["-PT2400000047H59M59.999999999S", "string with min hours"], + [{ hours: -2400000047, nanoseconds: -3599999999999 }, "property bag with min hours"], + ["-PT144000002879M59.999999999S", "string with min minutes"], + [{ minutes: -144000002879, nanoseconds: -59999999999 }, "property bag with min minutes"], + ["-PT8640000172799.999999999S", "string with min seconds"], + [{ seconds: -8640000172799, nanoseconds: -999999999 }, "property bag with min seconds"], +]; + +for (const [arg, descr] of minCases) { + const result = instance.add(arg); + TemporalHelpers.assertPlainDate(result, -271821, 4, "M04", 19, `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-duration-out-of-range.js new file mode 100644 index 0000000000..6067a9e27c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1970, 1, 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/PlainDate/prototype/add/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-invalid-property.js new file mode 100644 index 0000000000..af962db8fb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/add/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-mixed-sign.js new file mode 100644 index 0000000000..d5de33beb4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +["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/PlainDate/prototype/add/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-not-object.js new file mode 100644 index 0000000000..06546bf79e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Passing a primitive other than string to add() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/add/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-singular-properties.js new file mode 100644 index 0000000000..d37504ccc6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +[ + { 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/PlainDate/prototype/add/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..b0dc6ef7f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const resultHours = instance.add("-PT24.567890123H"); +TemporalHelpers.assertPlainDate(resultHours, 2000, 5, "M05", 1, "negative fractional hours"); + +const resultMinutes = instance.add("-PT1440.567890123M"); +TemporalHelpers.assertPlainDate(resultMinutes, 2000, 5, "M05", 1, "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-string.js new file mode 100644 index 0000000000..4155fc39a4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); +const result = instance.add("P3D"); +TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 5); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units-basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units-basic.js new file mode 100644 index 0000000000..b5f43668b0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units-basic.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.calendar.prototype.dateadd +description: Durations with units smaller than days are balanced +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1976, 11, 18); + +// lower units that don't balance up to a day +TemporalHelpers.assertPlainDate(date.add({ hours: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ minutes: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ seconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ milliseconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ microseconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ nanoseconds: 1 }), 1976, 11, "M11", 18); + +// lower units that balance up to a day or more +TemporalHelpers.assertPlainDate(date.add({ hours: 24 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ hours: 36 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ hours: 48 }), 1976, 11, "M11", 20); +TemporalHelpers.assertPlainDate(date.add({ minutes: 1440 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ seconds: 86400 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ milliseconds: 86400_000 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ microseconds: 86400_000_000 }), 1976, 11, "M11", 19); +TemporalHelpers.assertPlainDate(date.add({ nanoseconds: 86400_000_000_000 }), 1976, 11, "M11", 19); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units.js new file mode 100644 index 0000000000..c9d42a3b87 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/balance-smaller-units.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.calendar.prototype.dateadd +description: Durations with units smaller than days are balanced before adding, in the calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(0, 0, 0, 1, 24, 1440, 86400, 86400_000, 86400_000_000, 86400_000_000_000); + +const result = date.add(duration); +TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 9, "units smaller than days are balanced"); + +const resultString = date.add("P1DT24H1440M86400S"); +TemporalHelpers.assertPlainDate(resultString, 2000, 5, "M05", 6, "units smaller than days are balanced"); + +const resultPropBag = date.add({ days: 1, hours: 24, minutes: 1440, seconds: 86400, milliseconds: 86400_000, microseconds: 86400_000_000, nanoseconds: 86400_000_000_000 }); +TemporalHelpers.assertPlainDate(resultPropBag, 2000, 5, "M05", 9, "units smaller than days are balanced"); + +const negativeDuration = new Temporal.Duration(0, 0, 0, -1, -24, -1440, -86400, -86400_000, -86400_000_000, -86400_000_000_000); +const resultNegative = date.add(negativeDuration); +TemporalHelpers.assertPlainDate(resultNegative, 2000, 4, "M04", 25, "units smaller than days are balanced"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/basic.js new file mode 100644 index 0000000000..0d757e7129 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/basic.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.plaindate.prototype.add +description: Basic tests +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = Temporal.PlainDate.from("1976-11-18"); +TemporalHelpers.assertPlainDate(date.add({ years: 43 }), + 2019, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.add({ months: 3 }), + 1977, 2, "M02", 18); +TemporalHelpers.assertPlainDate(date.add({ days: 20 }), + 1976, 12, "M12", 8); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from("2019-01-31").add({ months: 1 }), + 2019, 2, "M02", 28); +TemporalHelpers.assertPlainDate(date.add(Temporal.Duration.from('P43Y')), + 2019, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2019-11-18').add({ years: -43 }), + 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('1977-02-18').add({ months: -3 }), + 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('1976-12-08').add({ days: -20 }), + 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2019-02-28').add({ months: -1 }), + 2019, 1, "M01", 28); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/branding.js new file mode 100644 index 0000000000..111bc9929c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/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.plaindate.prototype.add +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const add = Temporal.PlainDate.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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => add.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..66838eb6e1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +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/PlainDate/prototype/add/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/builtin.js new file mode 100644 index 0000000000..2ab3bd0c98 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.add), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.add), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.add), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.add.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/calendar-invalid-return.js new file mode 100644 index 0000000000..0cbfb34881 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/calendar-invalid-return.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.add +description: Throw when the returned value from the calendar's dateAdd method is not a PlainDate. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + dateAdd() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.PlainDate, "Temporal.PlainDate"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws(TypeError, () => plainDate.add({ years: 1 }), `Expected error with ${description}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/custom.js new file mode 100644 index 0000000000..f220ad6225 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/custom.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.plaindate.prototype.add +description: Basic tests with custom calendar +includes: [compareArray.js,temporalHelpers.js] +features: [Temporal] +---*/ + +const result = new Temporal.PlainDate(1920, 5, 3); +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(...args) { + ++calls; + assert.sameValue(args.length, 3, "Three arguments"); + assert.sameValue(args[0], plainDate, "First argument"); + TemporalHelpers.assertDuration(args[1], 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Second argument"); + assert.sameValue(typeof args[2], "object", "Third argument: type"); + assert.sameValue(Object.getPrototypeOf(args[2]), null, "Third argument: prototype"); + assert.compareArray(Object.keys(args[2]), [], "Third argument: keys"); + return result; + } +} +const calendar = new CustomCalendar(); +const plainDate = new Temporal.PlainDate(1976, 11, 18, calendar); +assert.sameValue(plainDate.add({ years: 43 }), result); +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..c68829b5a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.PlainDate.prototype.add throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plaindate.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); + +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/PlainDate/prototype/add/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/length.js new file mode 100644 index 0000000000..d5031ff92e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Temporal.PlainDate.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.PlainDate.prototype.add, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/limits.js new file mode 100644 index 0000000000..dedd779131 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/limits.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. + +/*--- +description: Temporal.PlainDate.prototype.add throws a RangeError if the calculation crosses a limit +esid: sec-temporal.plaindate.prototype.add +features: [Temporal] +---*/ + +const min = Temporal.PlainDate.from("-271821-04-19"); +const max = Temporal.PlainDate.from("+275760-09-13"); +["reject", "constrain"].forEach((overflow) => { + assert.throws(RangeError, () => min.add({ days: -1 }, { overflow }), `min with ${overflow}`); + assert.throws(RangeError, () => max.add({ days: 1 }, { overflow }), `max with ${overflow}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/name.js new file mode 100644 index 0000000000..21e3495429 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Temporal.PlainDate.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.PlainDate.prototype.add, "name", { + value: "add", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..44014165ee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.PlainDate.prototype.add throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plaindate.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); + +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/PlainDate/prototype/add/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..1dd6d9b79b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/add/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/not-a-constructor.js new file mode 100644 index 0000000000..4234996527 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: > + Temporal.PlainDate.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.PlainDate.prototype.add(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.add), false, + "isConstructor(Temporal.PlainDate.prototype.add)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-object.js new file mode 100644 index 0000000000..a827bcd6e8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.add({ months: 1 }, {}); +TemporalHelpers.assertPlainDate( + result1, 2000, 6, "M06", 2, + "options may be an empty plain object" +); + +const result2 = instance.add({ months: 1 }, () => {}); +TemporalHelpers.assertPlainDate( + result2, 2000, 6, "M06", 2, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-undefined.js new file mode 100644 index 0000000000..914f728206 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-undefined.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.plaindate.prototype.add +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 1, 31); +const duration = { months: 1 }; + +const explicit = date.add(duration, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = date.add(duration); +assert.sameValue(implicit.month, 2, "default overflow is constrain"); +assert.sameValue(implicit.day, 29, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/options-wrong-type.js new file mode 100644 index 0000000000..a068e69773 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/order-of-operations.js new file mode 100644 index 0000000000..d19a06209b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/order-of-operations.js @@ -0,0 +1,129 @@ +// |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.plaindate.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 = [ + // ToTemporalDurationRecord + "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", + // AddDate + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + // inside Calendar.p.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, 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 = [ + // ToTemporalDurationRecord + "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", + "get this.calendar.dateAdd", + // AddDate + "get options.overflow", + "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 operation"); + +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-constrain.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-constrain.js new file mode 100644 index 0000000000..6bf13939f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-constrain.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.plaindate.prototype.add +description: Constrains with overflow constrain +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const jan31 = Temporal.PlainDate.from("2020-01-31"); +TemporalHelpers.assertPlainDate(jan31.add({ months: 1 }, { overflow: "constrain" }), + 2020, 2, "M02", 29); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.js new file mode 100644 index 0000000000..0853583603 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-invalid-string.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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.add step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _balancedDuration_, _options_). +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(3, 3, 0, 3); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.add(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-reject.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-reject.js new file mode 100644 index 0000000000..aa9672d377 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/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.plaindate.prototype.add +description: Throws with overflow reject +features: [Temporal] +---*/ + +const jan31 = Temporal.PlainDate.from("2020-01-31"); +assert.throws(RangeError, () => jan31.add({ months: 1 }, { overflow: "reject" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-undefined.js new file mode 100644 index 0000000000..6f923341f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-undefined.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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.add step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _balancedDuration_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 31); +const duration = new Temporal.Duration(3, 1); + +const explicit = date.add(duration, { overflow: undefined }); +TemporalHelpers.assertPlainDate(explicit, 2003, 6, "M06", 30, "default overflow is constrain"); +const implicit = date.add(duration, {}); +TemporalHelpers.assertPlainDate(implicit, 2003, 6, "M06", 30, "default overflow is constrain"); +const lambda = date.add(duration, () => {}); +TemporalHelpers.assertPlainDate(lambda, 2003, 6, "M06", 30, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-wrong-type.js new file mode 100644 index 0000000000..98927d249e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/overflow-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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.add step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _balancedDuration_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(3, 3, 0, 3); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => date.add(duration, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDate(result, 2003, 8, "M08", 5, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/prop-desc.js new file mode 100644 index 0000000000..8bb7789f01 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/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.plaindate.prototype.add +description: The "add" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.add, + "function", + "`typeof PlainDate.prototype.add` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "add", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/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/PlainDate/prototype/add/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/subclassing-ignored.js new file mode 100644 index 0000000000..abbe09f5df --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.add +description: Objects of a subclass are never created as return values for add() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDate, + [2000, 5, 2], + "add", + [{ days: 1 }], + (result) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 3), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/branding.js new file mode 100644 index 0000000000..87e61c2db5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.calendarid +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const calendarId = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => calendarId.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..c4c44332c6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.calendarId; + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/prop-desc.js new file mode 100644 index 0000000000..bea8a35cce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.calendarid +description: The "calendarId" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/calendarId/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/calendarId/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/constructor.js new file mode 100644 index 0000000000..3363c592ed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.constructor +description: Test for Temporal.PlainDate.prototype.constructor. +info: The initial value of Temporal.PlainDate.prototype.constructor is %Temporal.PlainDate%. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainDate.prototype, "constructor", { + value: Temporal.PlainDate, + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/branding.js new file mode 100644 index 0000000000..307ed9319c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/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-get-temporal.plaindate.prototype.day +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const day = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "day").get; + +assert.sameValue(typeof day, "function"); + +assert.throws(TypeError, () => day.call(undefined), "undefined"); +assert.throws(TypeError, () => day.call(null), "null"); +assert.throws(TypeError, () => day.call(true), "true"); +assert.throws(TypeError, () => day.call(""), "empty string"); +assert.throws(TypeError, () => day.call(Symbol()), "symbol"); +assert.throws(TypeError, () => day.call(1), "1"); +assert.throws(TypeError, () => day.call({}), "plain object"); +assert.throws(TypeError, () => day.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => day.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..f80dbba88e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/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.plaindate.prototype.day +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 dayOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "day"); +Object.defineProperty(Temporal.Calendar.prototype, "day", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("day should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.day; + +Object.defineProperty(Temporal.Calendar.prototype, "day", dayOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/custom.js new file mode 100644 index 0000000000..c74d2b56c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/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.plaindate.prototype.day +description: Custom calendar tests for day(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + day(...args) { + ++calls; + assert.compareArray(args, [pd], "day arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.day; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/prop-desc.js new file mode 100644 index 0000000000..a51472e4cd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.day +description: The "day" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "day"); +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/PlainDate/prototype/day/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/validate-calendar-value.js new file mode 100644 index 0000000000..3cecbfd3a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/day/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.plaindate.prototype.day +description: Validate result returned from calendar day() 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 { + day() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.day, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/basic.js new file mode 100644 index 0000000000..e87712e78a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/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-get-temporal.plaindate.prototype.dayofweek +description: Basic tests for dayOfWeek(). +features: [Temporal] +---*/ + +for (let i = 1; i <= 7; ++i) { + const plainDate = new Temporal.PlainDate(1976, 11, 14 + i); + assert.sameValue(plainDate.dayOfWeek, i, `${plainDate} should be on day ${i}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/branding.js new file mode 100644 index 0000000000..24f4f288ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/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-get-temporal.plaindate.prototype.dayofweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const dayOfWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "dayOfWeek").get; + +assert.sameValue(typeof dayOfWeek, "function"); + +assert.throws(TypeError, () => dayOfWeek.call(undefined), "undefined"); +assert.throws(TypeError, () => dayOfWeek.call(null), "null"); +assert.throws(TypeError, () => dayOfWeek.call(true), "true"); +assert.throws(TypeError, () => dayOfWeek.call(""), "empty string"); +assert.throws(TypeError, () => dayOfWeek.call(Symbol()), "symbol"); +assert.throws(TypeError, () => dayOfWeek.call(1), "1"); +assert.throws(TypeError, () => dayOfWeek.call({}), "plain object"); +assert.throws(TypeError, () => dayOfWeek.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => dayOfWeek.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..06c14532d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/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.plaindate.prototype.dayofweek +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 dayOfWeekOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dayOfWeek"); +Object.defineProperty(Temporal.Calendar.prototype, "dayOfWeek", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dayOfWeek should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.dayOfWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "dayOfWeek", dayOfWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/custom.js new file mode 100644 index 0000000000..1f3ad60d72 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/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.plaindate.prototype.dayofweek +description: Custom calendar tests for dayOfWeek(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dayOfWeek(...args) { + ++calls; + assert.compareArray(args, [pd], "dayOfWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.dayOfWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/prop-desc.js new file mode 100644 index 0000000000..51629ce17f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.dayofweek +description: The "dayOfWeek" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "dayOfWeek"); +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/PlainDate/prototype/dayOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/validate-calendar-value.js new file mode 100644 index 0000000000..b3a5583270 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfWeek/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.plaindate.prototype.dayofweek +description: Validate result returned from calendar dayOfWeek() 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 { + dayOfWeek() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.dayOfWeek, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/basic.js new file mode 100644 index 0000000000..a0b4fc9967 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/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-get-temporal.plaindate.prototype.dayofyear +description: Basic tests for dayOfYear(). +features: [Temporal] +---*/ + +for (let i = 1; i <= 7; ++i) { + const plainDate = new Temporal.PlainDate(1976, 11, 14 + i); + assert.sameValue(plainDate.dayOfYear, 319 + i, `${plainDate} should be on day ${319 + i}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/branding.js new file mode 100644 index 0000000000..b9de274662 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/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-get-temporal.plaindate.prototype.dayofyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const dayOfYear = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "dayOfYear").get; + +assert.sameValue(typeof dayOfYear, "function"); + +assert.throws(TypeError, () => dayOfYear.call(undefined), "undefined"); +assert.throws(TypeError, () => dayOfYear.call(null), "null"); +assert.throws(TypeError, () => dayOfYear.call(true), "true"); +assert.throws(TypeError, () => dayOfYear.call(""), "empty string"); +assert.throws(TypeError, () => dayOfYear.call(Symbol()), "symbol"); +assert.throws(TypeError, () => dayOfYear.call(1), "1"); +assert.throws(TypeError, () => dayOfYear.call({}), "plain object"); +assert.throws(TypeError, () => dayOfYear.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => dayOfYear.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..b07a147c44 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/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.plaindate.prototype.dayofyear +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 dayOfYearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dayOfYear"); +Object.defineProperty(Temporal.Calendar.prototype, "dayOfYear", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("dayOfYear should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.dayOfYear; + +Object.defineProperty(Temporal.Calendar.prototype, "dayOfYear", dayOfYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/custom.js new file mode 100644 index 0000000000..3dc1efba96 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/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.plaindate.prototype.dayofyear +description: Custom calendar tests for dayOfYear(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dayOfYear(...args) { + ++calls; + assert.compareArray(args, [pd], "dayOfYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.dayOfYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/prop-desc.js new file mode 100644 index 0000000000..789531add6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.dayofyear +description: The "dayOfYear" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "dayOfYear"); +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/PlainDate/prototype/dayOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/validate-calendar-value.js new file mode 100644 index 0000000000..025b76dcdd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/dayOfYear/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.plaindate.prototype.dayofyear +description: Validate result returned from calendar dayOfYear() 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 { + dayOfYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.dayOfYear, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/basic.js new file mode 100644 index 0000000000..022b6d218a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.daysinmonth +description: Checking days in month for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDate(1976, 2, 18), 29], + [new Temporal.PlainDate(1976, 11, 18), 30], + [new Temporal.PlainDate(1976, 12, 18), 31], + [new Temporal.PlainDate(1977, 2, 18), 28], +]; +for (const [plainDate, expected] of tests) { + assert.sameValue(plainDate.daysInMonth, expected, `${expected} days in the month of ${plainDate}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/branding.js new file mode 100644 index 0000000000..a3650a8d64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/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-get-temporal.plaindate.prototype.daysinmonth +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInMonth = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => daysInMonth.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..f9b7544a2c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.daysInMonth; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInMonth", daysInMonthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/custom.js new file mode 100644 index 0000000000..b53aee4e36 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "daysInMonth arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.daysInMonth; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/prop-desc.js new file mode 100644 index 0000000000..00f8dc0aa0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.daysinmonth +description: The "daysInMonth" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/daysInMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInMonth/validate-calendar-value.js new file mode 100644 index 0000000000..2c903a74ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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/PlainDate/prototype/daysInWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/basic.js new file mode 100644 index 0000000000..8e470e1e42 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/basic.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-get-temporal.plaindate.prototype.daysinweek +description: Basic tests for daysInWeek(). +features: [Temporal] +---*/ + +const tests = [ + new Temporal.PlainDate(1976, 1, 1), + new Temporal.PlainDate(1976, 11, 18), + new Temporal.PlainDate(1976, 12, 31), +]; +for (const plainDate of tests) { + assert.sameValue(plainDate.daysInWeek, 7, `Seven days in the week of ${plainDate}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/branding.js new file mode 100644 index 0000000000..6e010896dd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/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-get-temporal.plaindate.prototype.daysinweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "daysInWeek").get; + +assert.sameValue(typeof daysInWeek, "function"); + +assert.throws(TypeError, () => daysInWeek.call(undefined), "undefined"); +assert.throws(TypeError, () => daysInWeek.call(null), "null"); +assert.throws(TypeError, () => daysInWeek.call(true), "true"); +assert.throws(TypeError, () => daysInWeek.call(""), "empty string"); +assert.throws(TypeError, () => daysInWeek.call(Symbol()), "symbol"); +assert.throws(TypeError, () => daysInWeek.call(1), "1"); +assert.throws(TypeError, () => daysInWeek.call({}), "plain object"); +assert.throws(TypeError, () => daysInWeek.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => daysInWeek.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..7eb50b35d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/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.plaindate.prototype.daysinweek +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 daysInWeekOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "daysInWeek"); +Object.defineProperty(Temporal.Calendar.prototype, "daysInWeek", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("daysInWeek should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.daysInWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInWeek", daysInWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/custom.js new file mode 100644 index 0000000000..3942f6a3af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/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.plaindate.prototype.daysinweek +description: Custom calendar tests for daysInWeek(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + daysInWeek(...args) { + ++calls; + assert.compareArray(args, [pd], "daysInWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.daysInWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/prop-desc.js new file mode 100644 index 0000000000..8d04f5afe1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.daysinweek +description: The "daysInWeek" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "daysInWeek"); +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/PlainDate/prototype/daysInWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/validate-calendar-value.js new file mode 100644 index 0000000000..e9eefdba7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInWeek/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.plaindate.prototype.daysinweek +description: Validate result returned from calendar daysInWeek() 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 { + daysInWeek() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.daysInWeek, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/basic.js new file mode 100644 index 0000000000..719a2fd527 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.daysinyear +description: Basic tests for daysInYear. +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainDate(1976, 11, 18)).daysInYear, 366, "leap year"); +assert.sameValue((new Temporal.PlainDate(1977, 11, 18)).daysInYear, 365, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/branding.js new file mode 100644 index 0000000000..c9caa7a2d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/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-get-temporal.plaindate.prototype.daysinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInYear = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => daysInYear.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..e38db3ec88 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.daysInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInYear", daysInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/custom.js new file mode 100644 index 0000000000..e9311cf1db --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "daysInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.daysInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/prop-desc.js new file mode 100644 index 0000000000..1e23a84375 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.daysinyear +description: The "daysInYear" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/daysInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/daysInYear/validate-calendar-value.js new file mode 100644 index 0000000000..3676842033 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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/PlainDate/prototype/equals/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..4ceb1ce39b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" }; +instance.equals(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..da799c2c7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-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.plaindate.prototype.equals +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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.equals(arg); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..190426203f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..d233f81391 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-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.plaindate.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'], ['day'], ['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.PlainDate(2000, 5, 2); + + assert.throws(RangeError, () => instance.equals(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-leap-second.js new file mode 100644 index 0000000000..6a8b47c6f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-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.plaindate.prototype.equals +description: Leap second is a valid ISO string for PlainDate +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2016, 12, 31); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.equals(arg); +assert.sameValue( + result1, + true, + "leap second is a valid ISO string for PlainDate" +); + +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 PlainDate" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-number.js new file mode 100644 index 0000000000..ce8907a765 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.equals(arg), + 'Numbers cannot be used in place of an ISO string for PlainDate' + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-invalid.js new file mode 100644 index 0000000000..3d78637c6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-invalid.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. + +/*--- +esid: sec-temporal.plaindate.prototype.equals +description: Appropriate error thrown when object argument is invalid +features: [Temporal] +---*/ + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); + +// End up in ISODateFromFields with missing fields +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals({ year: 1972, month: 7 }), "only year, month"); +assert.throws(TypeError, () => instance.equals({ year: 1972, month: 7 }), "only year, month"); +assert.throws(TypeError, () => instance.equals({ year: 1972, day: 7 }), "only year, day"); +assert.throws(TypeError, () => instance.equals(Temporal.PlainDate), "Temporal.PlainDate"); + +// Tries to get fields with an invalid receiver +assert.throws(TypeError, () => instance.equals(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-valid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-valid.js new file mode 100644 index 0000000000..635405aa14 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-object-valid.js @@ -0,0 +1,41 @@ +// |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.plaindate.prototype.equals +description: equals with a valid property bag +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +assert.sameValue(instance.equals({ year: 2000, month: 5, day: 2 }), true, "same date"); +assert.sameValue(instance.equals({ year: 2000, month: 5, day: 4 }), false, "different date"); + +const calendar = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "a", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +assert.sameValue(instance.withCalendar(calendar).equals({ year: 2000, month: 5, day: 2 }), + false, "different calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-plaindatetime.js new file mode 100644 index 0000000000..76e9e3464c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-plaindatetime.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.plaindate.prototype.equals +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindate.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.b: + b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then + i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const date = new Temporal.PlainDate(2000, 5, 2); + assert(date.equals(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..294ce1d006 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/equals/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..8182dd7587 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Leap second is a valid ISO string for a calendar in a property bag +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/equals/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..9510983c61 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +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: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/equals/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..637ccc83eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/equals/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..caacd9266a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/equals/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..dc0a12c58a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/equals/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..5bc1294f59 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..dfb9082b99 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-calendar-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.plaindate.prototype.equals +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02[u-ca=iso8601]", "without time or time zone"], + ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"], + ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"], + ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/equals/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..a8799d431c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-critical-unknown-annotation.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.plaindate.prototype.equals +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[!foo=bar]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/equals/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..7625140eec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-date-with-utc-offset.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.plaindate.prototype.equals +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const validStrings = [ + "2000-05-02T00+00:00", + "2000-05-02T00+00:00[UTC]", + "2000-05-02T00+00:00[!UTC]", + "2000-05-02T00-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 PlainDate` + ); +} + +const invalidStrings = [ + "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 PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js new file mode 100644 index 0000000000..f16df08054 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-invalid.js @@ -0,0 +1,64 @@ +// |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.plaindate.prototype.equals +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.equals(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..6d02de0a76 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/equals/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..f444e8bb2d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-multiple-time-zone.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.plaindate.prototype.equals +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[UTC][UTC]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/equals/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-time-separators.js new file mode 100644 index 0000000000..cf9bd7cf12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02T15:23", "uppercase T"], + ["2000-05-02t15:23", "lowercase T"], + ["2000-05-02 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/equals/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..621e81d60a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-time-zone-annotation.js @@ -0,0 +1,38 @@ +// |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.plaindate.prototype.equals +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02[Asia/Kolkata]", "named, with no time"], + ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"], + ["2000-05-02[+00:00]", "numeric, with no time"], + ["2000-05-02[!-02:30]", "numeric, with ! and no time"], + ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"], + ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"], + ["2000-05-02T15:23[-02:30]", "numeric, with no offset"], + ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"], + ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"], + ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"], + ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"], + ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/equals/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..9b669a031d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/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.plaindate.prototype.equals +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["2000-05-02[foo=bar]", "without time"], + ["2000-05-02T15:23[foo=bar]", "alone"], + ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"], + ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/equals/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..483bc36245 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: RangeError thrown if a string with UTC designator is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + "String with UTC designator should not be valid as a PlainDate" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string.js new file mode 100644 index 0000000000..436d598fc1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-string.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.plaindate.prototype.equals +description: equals with a valid string +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +assert.sameValue(instance.equals("2000-05-02"), true, "same date"); +assert.sameValue(instance.equals("2000-05-04"), false, "different date"); + +const calendar = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "a", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +assert.sameValue(instance.withCalendar(calendar).equals("2000-05-02"), false, "different calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..214b01461d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDate +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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.PlainDate, "Temporal.PlainDate, object"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.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/PlainDate/prototype/equals/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-convert.js new file mode 100644 index 0000000000..5136721a65 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-convert.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.plaindate.prototype.equals +description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated. +features: [Temporal] +---*/ + +class TZ extends Temporal.TimeZone { + constructor() { super("UTC") } + getOffsetNanosecondsFor() { throw new Test262Error() } +} + +const tz = new TZ(); +const arg = new Temporal.ZonedDateTime(0n, tz); +const instance = new Temporal.PlainDate(1976, 11, 18); + +assert.throws(Test262Error, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..ffee040bf0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-slots.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.plaindate.prototype.equals +description: Getters are not called when converting a ZonedDateTime to a PlainDate. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype); +const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"]; + +for (const property of getters) { + Object.defineProperty(Temporal.ZonedDateTime.prototype, property, { + get() { + actual.push(`get ${property}`); + const value = prototypeDescrs[property].get.call(this); + return { + toString() { + actual.push(`toString ${property}`); + return value.toString(); + }, + valueOf() { + actual.push(`valueOf ${property}`); + return value; + }, + }; + }, + }); +} + +const arg = new Temporal.ZonedDateTime(0n, "UTC"); +const instance = new Temporal.PlainDate(1976, 11, 18); +instance.equals(arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..bd6dae260c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.equals +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.equals(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..bc3c919fc5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.equals +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.equals(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..94a7516198 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.equals +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.equals(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..4d63297d7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.prototype.equals +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => date.equals(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/basic.js new file mode 100644 index 0000000000..67aabdfb73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/basic.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.plaindate.protoype.equals +description: basic tests +features: [Temporal] +---*/ + +const date1 = new Temporal.PlainDate(1976, 11, 18); +const date2 = new Temporal.PlainDate(1914, 2, 23); +const date3 = new Temporal.PlainDate(1914, 2, 23); +assert.sameValue(date1.equals(date2), false, "different dates"); +assert.sameValue(date2.equals(date3), true, "same dates"); +assert.sameValue(date2.equals(date2), true, "same objects"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/branding.js new file mode 100644 index 0000000000..4cb44e59d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const equals = Temporal.PlainDate.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +const args = [new Temporal.PlainDate(2022, 6, 22)]; + +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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => equals.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..542b98c5fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.equals(new Temporal.PlainDate(2000, 5, 2)); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/builtin.js new file mode 100644 index 0000000000..84abf7bc2e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.equals), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.equals), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.equals), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.equals.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-different.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-different.js new file mode 100644 index 0000000000..52352e6e43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-different.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.plaindate.protoype.equals +description: test if the calendar is compared +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CalendarTraceId extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this.id_ = id; + this.calls = 0; + } + get id() { + ++this.calls; + return this.id_; + } + toString() { + TemporalHelpers.assertUnreachable('toString should not be called'); + } +}; + +const calendar1 = new CalendarTraceId("a"); +const date1 = new Temporal.PlainDate(1914, 2, 23, calendar1); + +const calendar2 = new CalendarTraceId("b"); +const date2 = new Temporal.PlainDate(1914, 2, 23, calendar2); + +assert.sameValue(date1.equals(date2), false, "different calendars"); +assert.sameValue(calendar1.calls, 1, "calendar1 id getter calls"); +assert.sameValue(calendar2.calls, 1, "calendar2 id getter calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-same.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-same.js new file mode 100644 index 0000000000..15f32174c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-call-same.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.plaindate.protoype.equals +description: test if the calendar is compared +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CalendarTraceToString extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this.id_ = id; + this.calls = 0; + } + get id() { + ++this.calls; + return this.id_; + } + toString() { + TemporalHelpers.assertUnreachable('toString should not be called'); + } +}; + +const calendar1 = new CalendarTraceToString("a"); +const date1 = new Temporal.PlainDate(1914, 2, 23, calendar1); + +const calendar2 = new CalendarTraceToString("a"); +const date2 = new Temporal.PlainDate(1914, 2, 23, calendar2); + +assert.sameValue(date1.equals(date2), true, "same calendar id"); +assert.sameValue(calendar1.calls, 1, "calendar1 id getter calls"); +assert.sameValue(calendar2.calls, 1, "calendar2 id getter calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..bb9ddd5be6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/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.plaindate.prototype.equals +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.equals({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-fields-iterable.js new file mode 100644 index 0000000000..71b0cbeb7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-fields-iterable.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.plaindate.prototype.equals +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const date = new Temporal.PlainDate(2000, 5, 2, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +date.equals({ year: 2005, month: 6, day: 2, 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/PlainDate/prototype/equals/calendar-no-call.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-no-call.js new file mode 100644 index 0000000000..533feb35e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-no-call.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.plaindate.protoype.equals +description: test if the calendar is compared +features: [Temporal] +---*/ + +class CalendarTraceToString extends Temporal.Calendar { + constructor(id) { + super("iso8601"); + this.id_ = id; + this.calls = 0; + } + toString() { + ++this.calls; + return this.id_; + } +}; + +const calendar1 = new CalendarTraceToString("a"); +const date1 = new Temporal.PlainDate(1914, 2, 23, calendar1); + +const calendar2 = new CalendarTraceToString("b"); +const date2 = new Temporal.PlainDate(1914, 2, 22, calendar2); + +assert.sameValue(date1.equals(date2), false, "different ISO dates"); +assert.sameValue(calendar1.calls, 0, "calendar1 toString() calls"); +assert.sameValue(calendar2.calls, 0, "calendar2 toString() calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/calendar-temporal-object.js new file mode 100644 index 0000000000..4ea36b8a70 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindate.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.c: + c. 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 date = new Temporal.PlainDate(2000, 5, 2, temporalObject); + date.equals({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..fd8f9bcb1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].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/PlainDate/prototype/equals/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/length.js new file mode 100644 index 0000000000..ba9ffa7e32 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Temporal.PlainDate.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.PlainDate.prototype.equals, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/name.js new file mode 100644 index 0000000000..2e4a79abc7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: Temporal.PlainDate.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.PlainDate.prototype.equals, "name", { + value: "equals", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/not-a-constructor.js new file mode 100644 index 0000000000..c7fd5403e8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: > + Temporal.PlainDate.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.PlainDate.prototype.equals(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.equals), false, + "isConstructor(Temporal.PlainDate.prototype.equals)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..690c834d65 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.equals +description: The "equals" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.equals, + "function", + "`typeof PlainDate.prototype.equals` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/equals/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/year-zero.js new file mode 100644 index 0000000000..d62248d870 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/equals/year-zero.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.plaindate.prototype.equals +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T00:45", + "-000000-10-31T00:45+01:00", + "-000000-10-31T00:45+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/getCalendar/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/branding.js new file mode 100644 index 0000000000..d941757460 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getCalendar = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => getCalendar.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/builtin.js new file mode 100644 index 0000000000..31432c79ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.getCalendar), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.getCalendar), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.getCalendar), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.getCalendar.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/length.js new file mode 100644 index 0000000000..7ed0f11c4e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: Temporal.PlainDate.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.PlainDate.prototype.getCalendar, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/name.js new file mode 100644 index 0000000000..7a508ff62e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: Temporal.PlainDate.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.PlainDate.prototype.getCalendar, "name", { + value: "getCalendar", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/not-a-constructor.js new file mode 100644 index 0000000000..2cd96bf644 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: > + Temporal.PlainDate.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.PlainDate.prototype.getCalendar(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.getCalendar), false, + "isConstructor(Temporal.PlainDate.prototype.getCalendar)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/prop-desc.js new file mode 100644 index 0000000000..7087f4a214 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getcalendar +description: The "getCalendar" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.getCalendar, + "function", + "`typeof PlainDate.prototype.getCalendar` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "getCalendar", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getCalendar/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/getISOFields/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/branding.js new file mode 100644 index 0000000000..54eb2801ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getISOFields = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => getISOFields.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/builtin.js new file mode 100644 index 0000000000..6e413062fe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.getISOFields), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.getISOFields), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.getISOFields), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.getISOFields.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/custom.js new file mode 100644 index 0000000000..9af214f61e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: getISOFields does not call into user code. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarThrowEverything(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +const result = instance.getISOFields(); + +assert.sameValue(result.isoYear, 2000, "isoYear result"); +assert.sameValue(result.isoMonth, 5, "isoMonth result"); +assert.sameValue(result.isoDay, 2, "isoDay result"); +assert.sameValue(result.calendar, calendar, "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/field-names.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/field-names.js new file mode 100644 index 0000000000..e9fea72883 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Correct field names on the object returned from getISOFields +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); + +const result = date.getISOFields(); +assert.sameValue(result.isoYear, 2000, "isoYear result"); +assert.sameValue(result.isoMonth, 5, "isoMonth result"); +assert.sameValue(result.isoDay, 2, "isoDay result"); +assert.sameValue(result.calendar, "iso8601", "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/field-prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/field-prop-desc.js new file mode 100644 index 0000000000..3f033cb633 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Properties on the returned object have the correct descriptor +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +const expected = [ + "calendar", + "isoDay", + "isoMonth", + "isoYear", +]; + +const date = new Temporal.PlainDate(2000, 5, 2); +const result = date.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/PlainDate/prototype/getISOFields/field-traversal-order.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/field-traversal-order.js new file mode 100644 index 0000000000..6417f1d3fd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 date = new Temporal.PlainDate(2000, 5, 2); +const result = date.getISOFields(); + +assert.compareArray(Object.keys(result), expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/length.js new file mode 100644 index 0000000000..34dd97f568 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Temporal.PlainDate.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.PlainDate.prototype.getISOFields, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/name.js new file mode 100644 index 0000000000..c4bb4b942c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Temporal.PlainDate.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.PlainDate.prototype.getISOFields, "name", { + value: "getISOFields", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/not-a-constructor.js new file mode 100644 index 0000000000..3484530b71 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: > + Temporal.PlainDate.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.PlainDate.prototype.getISOFields(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.getISOFields), false, + "isConstructor(Temporal.PlainDate.prototype.getISOFields)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/prop-desc.js new file mode 100644 index 0000000000..49af4b6386 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: The "getISOFields" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.getISOFields, + "function", + "`typeof PlainDate.prototype.getISOFields` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "getISOFields", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/prototype.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/prototype.js new file mode 100644 index 0000000000..4dd3c9ebb6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.getisofields +description: Correct prototype on the object returned from getISOFields +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/getISOFields/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/getISOFields/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/inLeapYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/basic.js new file mode 100644 index 0000000000..8a7aabb4e8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.inleapyear +description: Basic test for inLeapYear +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainDate(1976, 11, 18)).inLeapYear, + true, "leap year"); +assert.sameValue((new Temporal.PlainDate(1977, 11, 18)).inLeapYear, + false, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/branding.js new file mode 100644 index 0000000000..ef7e7fb073 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/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-get-temporal.plaindate.prototype.inleapyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const inLeapYear = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => inLeapYear.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..690016923a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.inLeapYear; + +Object.defineProperty(Temporal.Calendar.prototype, "inLeapYear", inLeapYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/custom.js new file mode 100644 index 0000000000..5c7b285116 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "inLeapYear arguments"); + return true; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.inLeapYear; +assert.sameValue(result, true, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/prop-desc.js new file mode 100644 index 0000000000..9a1a9b4e48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.inleapyear +description: The "inLeapYear" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/inLeapYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/inLeapYear/validate-calendar-value.js new file mode 100644 index 0000000000..a21e641c24 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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.PlainDate(1981, 12, 15, calendar); + assert.sameValue(instance.inLeapYear, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/branding.js new file mode 100644 index 0000000000..c43783d1e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/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-get-temporal.plaindate.prototype.month +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const month = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => month.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..267c9f16a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.month; + +Object.defineProperty(Temporal.Calendar.prototype, "month", monthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/custom.js new file mode 100644 index 0000000000..bec164e029 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "month arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.month; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/prop-desc.js new file mode 100644 index 0000000000..185197f175 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.month +description: The "month" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/month/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/month/validate-calendar-value.js new file mode 100644 index 0000000000..cf18755457 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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/PlainDate/prototype/monthCode/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/branding.js new file mode 100644 index 0000000000..3c863bb2e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.monthcode +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthCode = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => monthCode.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..6d5f28b4e5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.monthCode; + +Object.defineProperty(Temporal.Calendar.prototype, "monthCode", monthCodeOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/custom.js new file mode 100644 index 0000000000..922cb28b48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "monthCode arguments"); + return "M01"; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.monthCode; +assert.sameValue(result, "M01", "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/prop-desc.js new file mode 100644 index 0000000000..5200447989 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.monthcode +description: The "monthCode" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/monthCode/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthCode/validate-calendar-value.js new file mode 100644 index 0000000000..0de050312b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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/PlainDate/prototype/monthsInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/basic.js new file mode 100644 index 0000000000..e87dbbc43b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/basic.js @@ -0,0 +1,14 @@ +// |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.plaindate.prototype.monthsinyear +description: Basic tests for monthsInYear(). +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(1976, 11, 18); +assert.sameValue(plainDate.monthsInYear, 12); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/branding.js new file mode 100644 index 0000000000..02ce82dd31 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/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-get-temporal.plaindate.prototype.monthsinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthsInYear = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => monthsInYear.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..10606a3ab6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.monthsInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "monthsInYear", monthsInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/custom.js new file mode 100644 index 0000000000..aa3d856629 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "monthsInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.monthsInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/prop-desc.js new file mode 100644 index 0000000000..a93ed88867 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.monthsinyear +description: The "monthsInYear" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/monthsInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/monthsInYear/validate-calendar-value.js new file mode 100644 index 0000000000..d0cf9588bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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/PlainDate/prototype/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/prop-desc.js new file mode 100644 index 0000000000..9f00e5b72c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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-plaindate-prototype +description: The "prototype" property of Temporal.PlainDate +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue(typeof Temporal.PlainDate.prototype, "object"); +assert.notSameValue(Temporal.PlainDate.prototype, null); + +verifyProperty(Temporal.PlainDate, "prototype", { + writable: false, + enumerable: false, + configurable: false, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..39f7b6b3fc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" }; +instance.since(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..c9a2c2753b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-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.plaindate.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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.since(arg); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..08aa6aebf8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..366ef14b08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-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.plaindate.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'], ['day'], ['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.PlainDate(2000, 5, 2); + + assert.throws(RangeError, () => instance.since(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-leap-second.js new file mode 100644 index 0000000000..37acb5ed55 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-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.plaindate.prototype.since +description: Leap second is a valid ISO string for PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2016, 12, 31); + +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 PlainDate" +); + +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 PlainDate" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-number.js new file mode 100644 index 0000000000..b7d52930c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.since(arg), + 'Numbers cannot be used in place of an ISO string for PlainDate' + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-plaindatetime.js new file mode 100644 index 0000000000..0524d02ca7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-plaindatetime.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.plaindate.since +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindate.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.b: + b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then + i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const date = new Temporal.PlainDate(2000, 5, 2); + const result = date.since(datetime); + assert.sameValue(result.total({ unit: "nanoseconds" }), 0, "time part dropped"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..f625f82cff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/since/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..b028699f45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1976, 11, 18); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/since/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..ef118b29ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/since/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..78077d1cb5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/since/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..4f7bc89d08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/since/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..13b4a25387 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/since/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..21dd6f91da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..c24c587a15 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-calendar-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.plaindate.prototype.since +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[u-ca=iso8601]", "without time or time zone"], + ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"], + ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"], + ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/since/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..d3ff358725 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-critical-unknown-annotation.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.plaindate.prototype.since +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[!foo=bar]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/since/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..577856f88a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-date-with-utc-offset.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.plaindate.prototype.since +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const validStrings = [ + "2000-05-02T00+00:00", + "2000-05-02T00+00:00[UTC]", + "2000-05-02T00+00:00[!UTC]", + "2000-05-02T00-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 PlainDate` + ); +} + +const invalidStrings = [ + "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 PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js new file mode 100644 index 0000000000..9767b0ef63 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-invalid.js @@ -0,0 +1,64 @@ +// |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.plaindate.prototype.since +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.since(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..5bb7388900 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/since/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..9f87b4dc02 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-multiple-time-zone.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.plaindate.prototype.since +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[UTC][UTC]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/since/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-time-separators.js new file mode 100644 index 0000000000..f12c529db2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02T15:23", "uppercase T"], + ["2000-05-02t15:23", "lowercase T"], + ["2000-05-02 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/since/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..acf7c2972f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-time-zone-annotation.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[Asia/Kolkata]", "named, with no time"], + ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"], + ["2000-05-02[+00:00]", "numeric, with no time"], + ["2000-05-02[!-02:30]", "numeric, with ! and no time"], + ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"], + ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"], + ["2000-05-02T15:23[-02:30]", "numeric, with no offset"], + ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"], + ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"], + ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"], + ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"], + ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/since/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..ba543410e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-unknown-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.plaindate.prototype.since +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[foo=bar]", "without time"], + ["2000-05-02T15:23[foo=bar]", "alone"], + ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"], + ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/since/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..1d6700d894 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: RangeError thrown if a string with UTC designator is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + "String with UTC designator should not be valid as a PlainDate" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-wrong-type.js new file mode 100644 index 0000000000..8fcddedfba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDate +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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.PlainDate, "Temporal.PlainDate, object"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.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/PlainDate/prototype/since/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-convert.js new file mode 100644 index 0000000000..5f1ee07422 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-convert.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.plaindate.prototype.since +description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated. +features: [Temporal] +---*/ + +class TZ extends Temporal.TimeZone { + constructor() { super("UTC") } + getOffsetNanosecondsFor() { throw new Test262Error() } +} + +const tz = new TZ(); +const arg = new Temporal.ZonedDateTime(0n, tz); +const instance = new Temporal.PlainDate(1976, 11, 18); + +assert.throws(Test262Error, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..1270b6d99f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-slots.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.plaindate.prototype.since +description: Getters are not called when converting a ZonedDateTime to a PlainDate. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype); +const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"]; + +for (const property of getters) { + Object.defineProperty(Temporal.ZonedDateTime.prototype, property, { + get() { + actual.push(`get ${property}`); + const value = prototypeDescrs[property].get.call(this); + return { + toString() { + actual.push(`toString ${property}`); + return value.toString(); + }, + valueOf() { + actual.push(`valueOf ${property}`); + return value; + }, + }; + }, + }); +} + +const arg = new Temporal.ZonedDateTime(0n, "UTC"); +const instance = new Temporal.PlainDate(1976, 11, 18); +instance.since(arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..8c06d06e06 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.since +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.since(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..2fd89d1bc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.since +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.since(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..41e03c66bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.since +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.since(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..46d51c9016 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.prototype.since +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => date.since(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/basic.js new file mode 100644 index 0000000000..0f7e7221d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/basic.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.plaindate.prototype.since +description: Basic tests for since(). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(1969, 7, 24); +const plainDate2 = Temporal.PlainDate.from({ year: 1969, month: 10, day: 5 }); +TemporalHelpers.assertDuration(plainDate2.since(plainDate), 0, 0, 0, /* days = */ 73, 0, 0, 0, 0, 0, 0, "same year"); + +const earlier = new Temporal.PlainDate(1969, 7, 24); +const later = new Temporal.PlainDate(1996, 3, 3); +const duration = later.since(earlier); +TemporalHelpers.assertDuration(duration, 0, 0, 0, /* days = */ 9719, 0, 0, 0, 0, 0, 0, "different year"); + +TemporalHelpers.assertDuration(plainDate.since({ year: 2019, month: 7, day: 24 }), 0, 0, 0, /* days = */ -18262, 0, 0, 0, 0, 0, 0, "option bag"); +TemporalHelpers.assertDuration(plainDate.since("2019-07-24"), 0, 0, 0, /* days = */ -18262, 0, 0, 0, 0, 0, 0, "string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/branding.js new file mode 100644 index 0000000000..b6b33a0ed1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/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.plaindate.prototype.since +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const since = Temporal.PlainDate.prototype.since; + +assert.sameValue(typeof since, "function"); + +const args = [new Temporal.PlainDate(2022, 6, 22)]; + +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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => since.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..48abc72656 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.since(new Temporal.PlainDate(1999, 4, 1)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/builtin.js new file mode 100644 index 0000000000..2a0e1056df --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.since), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.since), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.since), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.since.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..ccbfe65104 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateadd-called-with-plaindate-instance.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.plaindate.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.PlainDate(1970, 1, 1, calendar); +calendar.specificPlainDate = instance; +instance.since(new Temporal.PlainDate(2000, 5, 2, calendar), { smallestUnit: "month" }); +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/PlainDate/prototype/since/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..72eb3ada42 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.since({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..68079f9d32 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, calendar); +const argument = new Temporal.PlainDate(2022, 6, 14, calendar); +instance.since(argument, { largestUnit: "months" }); +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/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..96382a3764 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.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.plaindate.prototype.since +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plaindate.prototype.since steps 13–14: + 13. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _largestUnit_). + 14. Let _result_ be ? CalendarDateUntil(_temporalDate_.[[Calendar]], _other_, _temporalDate_, _untilOptions_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainDate(2000, 5, 2, calendar); + const later = new Temporal.PlainDate(2001, 6, 3, calendar); + later.since(earlier, { largestUnit }); + }, + { + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-fields-iterable.js new file mode 100644 index 0000000000..73db3c85dd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-fields-iterable.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.plaindate.prototype.since +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const date = new Temporal.PlainDate(2000, 5, 2, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +date.since({ year: 2005, month: 6, day: 2, 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/PlainDate/prototype/since/calendar-id-match.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-id-match.js new file mode 100644 index 0000000000..9191a3635f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-id-match.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.plaindate.prototype.since +description: Calculation is performed if calendars' toString results match +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +class Calendar1 extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + toString() { + return "A"; + } +} +class Calendar2 extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + toString() { + return "A"; + } +} + +const plainDate1 = new Temporal.PlainDate(2000, 1, 1, new Calendar1()); +const plainDate2 = new Temporal.PlainDate(2000, 1, 2, new Calendar2()); +TemporalHelpers.assertDuration(plainDate2.since(plainDate1), 0, 0, 0, /* days = */ 1, 0, 0, 0, 0, 0, 0); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.js new file mode 100644 index 0000000000..f008696b77 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-invalid-return.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.plaindate.prototype.since +description: Throw when the returned value from the calendar's dateUntil method is not a Duration. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + dateUntil() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.Duration, "Temporal.Duration"], + [Temporal.Duration.prototype, "Temporal.Duration.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws( + TypeError, + () => plainDate.since("2022-06-20", { largestUnit: "years" }), + `Expected error with ${description}` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-mismatch.js new file mode 100644 index 0000000000..1537dda6ee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-mismatch.js @@ -0,0 +1,62 @@ +// |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.plaindate.prototype.since +description: RangeError thrown if calendars' id properties do not match +features: [Temporal] +---*/ + +const calendar1 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "A", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const calendar2 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "B", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const plainDate1 = new Temporal.PlainDate(2000, 1, 1, calendar1); +const plainDate2 = new Temporal.PlainDate(2000, 1, 1, calendar2); +assert.throws(RangeError, () => plainDate1.since(plainDate2)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/calendar-temporal-object.js new file mode 100644 index 0000000000..c99733f2d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindate.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.c: + c. 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 date = new Temporal.PlainDate(2000, 5, 2, temporalObject); + date.since({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/custom.js new file mode 100644 index 0000000000..7aa8c4de2e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/custom.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.plaindate.prototype.since +description: Basic tests with custom calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const result = new Temporal.Duration(1, 3, 5, 7, 9); +const options = { largestUnit: "years" }; +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateUntil(...args) { + ++calls; + assert.sameValue(args.length, 3, "Three arguments"); + assert.sameValue(args[0], plainDate, "First argument"); + assert.sameValue(args[1], other, "Second argument"); + assert.sameValue(args[2].largestUnit, "year", "Third argument: largestUnit"); + return result; + } +} +const calendar = new CustomCalendar(); +const plainDate = new Temporal.PlainDate(1976, 11, 18, calendar); +const other = new Temporal.PlainDate(2022, 6, 20, calendar); +TemporalHelpers.assertDuration(plainDate.since(other, options), + -1, -3, -5, -7, 0, 0, 0, 0, 0, 0, "result"); +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-month.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-month.js new file mode 100644 index 0000000000..4bce5ba5d5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-month.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.plaindate.prototype.since +description: since() should take length of month into account. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate1 = Temporal.PlainDate.from("2019-01-01"); +const plainDate2 = Temporal.PlainDate.from("2019-02-01"); +const plainDate3 = Temporal.PlainDate.from("2019-03-01"); +TemporalHelpers.assertDuration(plainDate2.since(plainDate1), 0, 0, 0, /* days = */ 31, 0, 0, 0, 0, 0, 0, "January 2019"); +TemporalHelpers.assertDuration(plainDate3.since(plainDate2), 0, 0, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "February 2019"); + +const plainDate4 = Temporal.PlainDate.from("2020-02-01"); +const plainDate5 = Temporal.PlainDate.from("2020-03-01"); +TemporalHelpers.assertDuration(plainDate5.since(plainDate4), 0, 0, 0, /* days = */ 29, 0, 0, 0, 0, 0, 0, "February 2020"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-year.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-year.js new file mode 100644 index 0000000000..852c3062f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/days-in-year.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.plaindate.prototype.since +description: since() should take length of year into account. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate1 = Temporal.PlainDate.from("2019-01-01"); +const plainDate2 = Temporal.PlainDate.from("2020-01-01"); +const plainDate3 = Temporal.PlainDate.from("2021-01-01"); +TemporalHelpers.assertDuration(plainDate2.since(plainDate1), 0, 0, 0, /* days = */ 365, 0, 0, 0, 0, 0, 0, "From January 2019"); +TemporalHelpers.assertDuration(plainDate3.since(plainDate2), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "From January 2020"); + +const plainDate4 = Temporal.PlainDate.from("2019-06-01"); +const plainDate5 = Temporal.PlainDate.from("2020-06-01"); +const plainDate6 = Temporal.PlainDate.from("2021-06-01"); +TemporalHelpers.assertDuration(plainDate5.since(plainDate4), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "From June 2019"); +TemporalHelpers.assertDuration(plainDate6.since(plainDate5), 0, 0, 0, /* days = */ 365, 0, 0, 0, 0, 0, 0, "From June 2020"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..33d5c6c536 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].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/PlainDate/prototype/since/largestunit-default.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.js new file mode 100644 index 0000000000..347254e0ab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-default.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.plaindate.prototype.since +description: Default value for largestUnit option is days +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = Temporal.PlainDate.from("2020-02-01"); +const feb21 = Temporal.PlainDate.from("2021-02-01"); +TemporalHelpers.assertDuration(feb21.since(feb20), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no options"); +TemporalHelpers.assertDuration(feb21.since(feb20, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined options"); +TemporalHelpers.assertDuration(feb21.since(feb20, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "days"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "auto"); +TemporalHelpers.assertDuration(feb21.since(feb20, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.js new file mode 100644 index 0000000000..89fbfe8c6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-higher-units.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.plaindate.prototype.since +description: Tests calculations with higher largestUnit than the default of 'days' +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1969, 7, 24); +const later = Temporal.PlainDate.from({ year: 2019, month: 7, day: 24 }); +const duration = later.since(date, { largestUnit: "years" }); +TemporalHelpers.assertDuration(duration, /* years = */ 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, "crossing epoch"); + +const feb20 = Temporal.PlainDate.from("2020-02-01"); +const feb21 = Temporal.PlainDate.from("2021-02-01"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "years" }), /* years = */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, years"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "months" }), 0, /* months = */ 12, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, months"); +TemporalHelpers.assertDuration(feb21.since(feb20, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, "start of February, weeks"); + +const lastFeb20 = Temporal.PlainDate.from("2020-02-29"); +const lastFeb21 = Temporal.PlainDate.from("2021-02-28"); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "years" }), 0, /* months = */ 11, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "end of February, years"); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "months" }), 0, /* months = */ 11, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "end of February, months"); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 1, 0, 0, 0, 0, 0, 0, "end of February, weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.js new file mode 100644 index 0000000000..f62f2effe5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-invalid-string.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.plaindate.prototype.since +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..cd93f33fd9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-plurals-accepted.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.plaindate.prototype.since +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 12); +const validUnits = [ + "year", + "month", + "week", + "day", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => later.since(earlier, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..f7ab10f829 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const units = ["years", "months", "weeks", "days"]; +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/PlainDate/prototype/since/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-undefined.js new file mode 100644 index 0000000000..f12b94d2d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-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.plaindate.prototype.since +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); + +const explicit = later.since(earlier, { largestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default largestUnit is day"); +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default largestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit-wrong-type.js new file mode 100644 index 0000000000..6fc693637d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "year", + (largestUnit) => later.since(earlier, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit.js new file mode 100644 index 0000000000..1f78521659 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/largestunit.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.plaindate.prototype.since +description: Specify behavior of PlainDate.since when largest specified unit is years or months. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ +const pd1 = new Temporal.PlainDate(2020, 11, 1); +const pd2 = new Temporal.PlainDate(2021, 11, 30); +TemporalHelpers.assertDuration(pd2.since(pd1), 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 'does not include higher units than necessary (largest unit unspecified)'); +TemporalHelpers.assertDuration(pd2.since(pd1, { largestUnit: 'months' }), 0, 12, 0, 29, 0, 0, 0, 0, 0, 0, 'does not include higher units than necessary (largest unit is months)'); +TemporalHelpers.assertDuration(pd2.since(pd1, { largestUnit: 'years' }), 1, 0, 0, 29, 0, 0, 0, 0, 0, 0, 'does not include higher units than necessary (largest unit is years)'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/length.js new file mode 100644 index 0000000000..32fd4e2a83 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Temporal.PlainDate.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.PlainDate.prototype.since, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/name.js new file mode 100644 index 0000000000..70e86fb9e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Temporal.PlainDate.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.PlainDate.prototype.since, "name", { + value: "since", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/not-a-constructor.js new file mode 100644 index 0000000000..addff2bce7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: > + Temporal.PlainDate.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.PlainDate.prototype.since(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.since), false, + "isConstructor(Temporal.PlainDate.prototype.since)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/options-object.js new file mode 100644 index 0000000000..e3cfe462a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.since(new Temporal.PlainDate(1976, 11, 18), {}); +TemporalHelpers.assertDuration( + result1, 0, 0, 0, 8566, 0, 0, 0, 0, 0, 0, + "options may be an empty plain object" +); + +const result2 = instance.since(new Temporal.PlainDate(1976, 11, 18), () => {}); +TemporalHelpers.assertDuration( + result2, 0, 0, 0, 8566, 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/PlainDate/prototype/since/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/options-wrong-type.js new file mode 100644 index 0000000000..6c95b9436c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainDate(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js new file mode 100644 index 0000000000..1214a1cd49 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js @@ -0,0 +1,213 @@ +// |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.plaindate.prototype.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDate + "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.dateFromFields", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "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.dateFromFields", + // 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 actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); + +const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "days", 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); + +// basic order of observable operations with calendar call, without rounding: +instance.since(otherDatePropertyBag, createOptionsObserver({ largestUnit: "years" })); +assert.compareArray(actual, expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", +]), "order of operations"); +actual.splice(0); // clear + +// short-circuit for identical objects: +const identicalPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.since(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations with identical dates"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 12.d + "call this.calendar.dateAdd", // 12.f + "call this.calendar.dateUntil", // 12.n + "call this.calendar.dateAdd", // 12.x MoveRelativeDate + // (12.r 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(otherDatePropertyBag, 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 otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 12.d + "call this.calendar.dateAdd", // 12.f + "call this.calendar.dateAdd", // 12.x MoveRelativeDate + // (12.n not called because months and weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.since(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 13.c + "call this.calendar.dateAdd", // 13.e + "call this.calendar.dateAdd", // 13.w MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil" // 10.e +]); +instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateUntil", // 14.f + "call this.calendar.dateAdd", // 14.p MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 16 + "call this.calendar.dateUntil" // 17 +]); +instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with smallestUnit = weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/prop-desc.js new file mode 100644 index 0000000000..cbebd49dad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/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.plaindate.prototype.since +description: The "since" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.since, + "function", + "`typeof PlainDate.prototype.since` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "since", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/round-cross-unit-boundary.js new file mode 100644 index 0000000000..48f8b822c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2022, 1, 1); +const later = new Temporal.PlainDate(2023, 12, 25); +const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" }); +TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "-1 year -11 months balances to -2 years"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-relative.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-relative.js new file mode 100644 index 0000000000..fe26ed0e44 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-relative.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.plaindate.prototype.since +description: Should round relative to the receiver. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date1 = Temporal.PlainDate.from("2019-01-01"); +const date2 = Temporal.PlainDate.from("2019-02-15"); + +TemporalHelpers.assertDuration( + date2.since(date1, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ 1, 0, 0, 0, 0, 0, 0, 0, 0); +TemporalHelpers.assertDuration( + date1.since(date2, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ -2, 0, 0, 0, 0, 0, 0, 0, 0); + +const cases = [ + ["2019-03-01", "2019-01-29", 1, 3], + ["2019-01-29", "2019-03-01", -1, -1], + ["2019-03-29", "2019-01-30", 1, 29], + ["2019-01-30", "2019-03-29", -1, -29], + ["2019-03-30", "2019-01-31", 1, 28], + ["2019-01-31", "2019-03-30", -1, -30], + ["2019-03-31", "2019-01-31", 2, 0], + ["2019-01-31", "2019-03-31", -2, 0] +]; +for (const [end, start, months, days] of cases) { + const result = Temporal.PlainDate.from(end).since(start, { largestUnit: "months" }); + TemporalHelpers.assertDuration(result, 0, months, 0, days, 0, 0, 0, 0, 0, 0, `${end} - ${start}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-zero-year-month-week-length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-zero-year-month-week-length.js new file mode 100644 index 0000000000..0815cd30a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/rounding-zero-year-month-week-length.js @@ -0,0 +1,34 @@ +// |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.plaindate.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 d1 = new Temporal.PlainDate(1970, 1, 1, cal); +const d2 = new Temporal.PlainDate(1971, 1, 1, cal); + +assert.throws(RangeError, () => d1.since(d2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => d1.since(d2, { smallestUnit: "months" }), "zero month length handled correctly"); +assert.throws(RangeError, () => d1.since(d2, { smallestUnit: "weeks" }), "zero week length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-nan.js new file mode 100644 index 0000000000..147002ea9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.prototype.since step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js new file mode 100644 index 0000000000..350d8aea2e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.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.plaindate.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.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +const result = later.since(earlier, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, "roundingIncrement 2.5 truncates to 2"); +const result2 = later.since(earlier, { smallestUnit: "days", roundingIncrement: 1e9 + 0.5, roundingMode: "expand" }); +TemporalHelpers.assertDuration(result2, 0, 0, 0, 1e9, 0, 0, 0, 0, 0, 0, "roundingIncrement 1e9 + 0.5 truncates to 1e9"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..b08717d226 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +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/PlainDate/prototype/since/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-undefined.js new file mode 100644 index 0000000000..929967235b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-undefined.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.plaindate.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.plaindate.prototype.since step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); + +const explicit = later.since(earlier, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +// See options-undefined.js for {} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..c7ed2fee9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.prototype.since step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => later.since(earlier, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js new file mode 100644 index 0000000000..5873e3b25f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.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.plaindate.prototype.since +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = Temporal.PlainDate.from("2019-01-08"); +const later = Temporal.PlainDate.from("2021-09-07"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }), + /* years = */ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, "years"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "months", roundingIncrement: 10, roundingMode: "halfExpand" }), + 0, /* months = */ 30, 0, 0, 0, 0, 0, 0, 0, 0, "months"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "weeks", roundingIncrement: 12, roundingMode: "halfExpand" }), + 0, 0, /* weeks = */ 144, 0, 0, 0, 0, 0, 0, 0, "weeks"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "days", roundingIncrement: 100, roundingMode: "halfExpand" }), + 0, 0, 0, /* days = */ 1000, 0, 0, 0, 0, 0, 0, "days"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-ceil.js new file mode 100644 index 0000000000..8a64c7afe3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-ceil.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-2]], + ["months", [0, 32], [0, -31]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-expand.js new file mode 100644 index 0000000000..a869c012ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-expand.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-floor.js new file mode 100644 index 0000000000..6048242bbf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-floor.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [2], [-3]], + ["months", [0, 31], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js new file mode 100644 index 0000000000..7bdf5db27f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js new file mode 100644 index 0000000000..f95cb286eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfExpand.js new file mode 100644 index 0000000000..1b137fa714 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfExpand.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js new file mode 100644 index 0000000000..fd2112d032 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..e7e36d28f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-invalid-string.js new file mode 100644 index 0000000000..fe4245ee3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/since/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-trunc.js new file mode 100644 index 0000000000..6b2deedab4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-trunc.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.since +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [2], [-2]], + ["months", [0, 31], [0, -31]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/since/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-undefined.js new file mode 100644 index 0000000000..d0fe47a652 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 1, 1); + +const later1 = new Temporal.PlainDate(2005, 2, 20); +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.PlainDate(2005, 12, 15); +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/PlainDate/prototype/since/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/roundingmode-wrong-type.js new file mode 100644 index 0000000000..9f69923d72 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/since/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/since/smallestunit-higher-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-higher-units.js new file mode 100644 index 0000000000..906fa73ecc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-higher-units.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.plaindate.prototype.since +description: Tests calculations with higher smallestUnit than the default of "days" +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = Temporal.PlainDate.from("2019-01-08"); +const later = Temporal.PlainDate.from("2021-09-07"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "years", roundingMode: "halfExpand" }), + /* years = */ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, "years"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ 32, 0, 0, 0, 0, 0, 0, 0, 0, "months"); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "weeks", roundingMode: "halfExpand" }), + 0, 0, /* weeks = */ 139, 0, 0, 0, 0, 0, 0, 0, "weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.js new file mode 100644 index 0000000000..40b84325d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-invalid-string.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.plaindate.prototype.since +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..e60ddefa73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-plurals-accepted.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.plaindate.prototype.since +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 12); +const validUnits = [ + "year", + "month", + "week", + "day", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => later.since(earlier, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-undefined.js new file mode 100644 index 0000000000..a27bf87ec4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); + +const explicit = later.since(earlier, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default smallestUnit is day"); +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default smallestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/smallestunit-wrong-type.js new file mode 100644 index 0000000000..c55f5caf9a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.since +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/since/weeks-months.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/weeks-months.js new file mode 100644 index 0000000000..d22b6914ea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/weeks-months.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.plaindate.prototype.since +description: since() should not return weeks and months together. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1969, 7, 24); +const laterDate = new Temporal.PlainDate(1969, 9, 4); +TemporalHelpers.assertDuration(laterDate.since(date, { largestUnit: "weeks" }), + 0, 0, /* weeks = */ 6, 0, 0, 0, 0, 0, 0, 0, "weeks"); +TemporalHelpers.assertDuration(laterDate.since(date, { largestUnit: "months" }), + 0, /* months = */ 1, 0, 11, 0, 0, 0, 0, 0, 0, "months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/year-zero.js new file mode 100644 index 0000000000..d894c5036c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/since/year-zero.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.plaindate.prototype.since +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T00:45", + "-000000-10-31T00:45+01:00", + "-000000-10-31T00:45+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/subtract/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-duration-max.js new file mode 100644 index 0000000000..09d307861f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1970, 1, 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"], + ["P14285714W3DT23H59M59.999999999S", "string with max weeks"], + [{ weeks: 14285714, days: 3, nanoseconds: 86399999999999 }, "property bag with max weeks"], + ["P100000001DT23H59M59.999999999S", "string with max days"], + [{ days: 100000001, nanoseconds: 86399999999999 }, "property bag with max days"], + ["PT2400000047H59M59.999999999S", "string with max hours"], + [{ hours: 2400000047, nanoseconds: 3599999999999 }, "property bag with max hours"], + ["PT144000002879M59.999999999S", "string with max minutes"], + [{ minutes: 144000002879, nanoseconds: 59999999999 }, "property bag with max minutes"], + ["PT8640000172799.999999999S", "string with max seconds"], + [{ seconds: 8640000172799, nanoseconds: 999999999 }, "property bag with max seconds"], +]; + +for (const [arg, descr] of maxCases) { + const result = instance.subtract(arg); + TemporalHelpers.assertPlainDate(result, -271821, 4, "M04", 19, `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.assertPlainDate(result, 275760, 9, "M09", 13, `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-duration-out-of-range.js new file mode 100644 index 0000000000..5dbcc8de3c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1970, 1, 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/PlainDate/prototype/subtract/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-invalid-property.js new file mode 100644 index 0000000000..85deb4d369 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/subtract/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-mixed-sign.js new file mode 100644 index 0000000000..82ce5272a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +["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/PlainDate/prototype/subtract/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-not-object.js new file mode 100644 index 0000000000..7bf90c463d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Passing a primitive other than string to subtract() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/subtract/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-singular-properties.js new file mode 100644 index 0000000000..a9c76a26de --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +[ + { 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/PlainDate/prototype/subtract/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..21fe56e530 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const resultHours = instance.subtract("-PT24.567890123H"); +TemporalHelpers.assertPlainDate(resultHours, 2000, 5, "M05", 3, "negative fractional hours"); + +const resultMinutes = instance.subtract("-PT1440.567890123M"); +TemporalHelpers.assertPlainDate(resultMinutes, 2000, 5, "M05", 3, "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-string.js new file mode 100644 index 0000000000..168af12c46 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); +const result = instance.subtract("P3D"); +TemporalHelpers.assertPlainDate(result, 2000, 4, "M04", 29); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units-basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units-basic.js new file mode 100644 index 0000000000..9c3556b488 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units-basic.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.calendar.prototype.dateadd +description: Durations with units smaller than days are balanced +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1976, 11, 18); + +// lower units that don't balance up to a day +TemporalHelpers.assertPlainDate(date.subtract({ hours: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ minutes: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ seconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ milliseconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ microseconds: 1 }), 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ nanoseconds: 1 }), 1976, 11, "M11", 18); + +// lower units that balance up to a day or more +TemporalHelpers.assertPlainDate(date.subtract({ hours: 24 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ hours: 36 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ hours: 48 }), 1976, 11, "M11", 16); +TemporalHelpers.assertPlainDate(date.subtract({ minutes: 1440 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ seconds: 86400 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ milliseconds: 86400_000 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ microseconds: 86400_000_000 }), 1976, 11, "M11", 17); +TemporalHelpers.assertPlainDate(date.subtract({ nanoseconds: 86400_000_000_000 }), 1976, 11, "M11", 17); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units.js new file mode 100644 index 0000000000..5c04b17496 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/balance-smaller-units.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.calendar.prototype.dateadd +description: Durations with units smaller than days are balanced before adding, in the calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(0, 0, 0, 1, 24, 1440, 86400, 86400_000, 86400_000_000, 86400_000_000_000); + +const result = date.subtract(duration); +TemporalHelpers.assertPlainDate(result, 2000, 4, "M04", 25, "units smaller than days are balanced"); + +const resultString = date.subtract("P1DT24H1440M86400S"); +TemporalHelpers.assertPlainDate(resultString, 2000, 4, "M04", 28, "units smaller than days are balanced"); + +const resultPropBag = date.subtract({ days: 1, hours: 24, minutes: 1440, seconds: 86400, milliseconds: 86400_000, microseconds: 86400_000_000, nanoseconds: 86400_000_000_000 }); +TemporalHelpers.assertPlainDate(resultPropBag, 2000, 4, "M04", 25, "units smaller than days are balanced"); + +const negativeDuration = new Temporal.Duration(0, 0, 0, -1, -24, -1440, -86400, -86400_000, -86400_000_000, -86400_000_000_000); +const resultNegative = date.subtract(negativeDuration); +TemporalHelpers.assertPlainDate(resultNegative, 2000, 5, "M05", 9, "units smaller than days are balanced"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/basic.js new file mode 100644 index 0000000000..a7a928366b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/basic.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.plaindate.prototype.subtract +description: Basic tests +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = Temporal.PlainDate.from("2019-11-18"); +TemporalHelpers.assertPlainDate(date.subtract({ years: 43 }), + 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(date.subtract({ months: 11 }), + 2018, 12, "M12", 18); +TemporalHelpers.assertPlainDate(date.subtract({ days: 20 }), + 2019, 10, "M10", 29); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2019-02-28').subtract({ months: 1 }), + 2019, 1, "M01", 28); +TemporalHelpers.assertPlainDate(date.subtract(Temporal.Duration.from('P43Y')), + 1976, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('1976-11-18').subtract({ years: -43 }), + 2019, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2018-12-18').subtract({ months: -11 }), + 2019, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2019-10-29').subtract({ days: -20 }), + 2019, 11, "M11", 18); +TemporalHelpers.assertPlainDate(Temporal.PlainDate.from('2019-01-28').subtract({ months: -1 }), + 2019, 2, "M02", 28); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/branding.js new file mode 100644 index 0000000000..86a63ad288 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/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.plaindate.prototype.subtract +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const subtract = Temporal.PlainDate.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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => subtract.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..3eacf11a43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +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/PlainDate/prototype/subtract/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/builtin.js new file mode 100644 index 0000000000..b0eeade73a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.subtract), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.subtract), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.subtract), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.subtract.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/calendar-invalid-return.js new file mode 100644 index 0000000000..57c5dfcee1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/calendar-invalid-return.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.subtract +description: Throw when the returned value from the calendar's dateAdd method is not a PlainDate. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + dateAdd() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.PlainDate, "Temporal.PlainDate"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws(TypeError, () => plainDate.subtract({ years: 1 }), `Expected error with ${description}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/custom.js new file mode 100644 index 0000000000..06ac7f743d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/custom.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.plaindate.prototype.subtract +description: Basic tests with custom calendar +includes: [compareArray.js,temporalHelpers.js] +features: [Temporal] +---*/ + +const result = new Temporal.PlainDate(1920, 5, 3); +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(...args) { + ++calls; + assert.sameValue(args.length, 3, "Three arguments"); + assert.sameValue(args[0], plainDate, "First argument"); + TemporalHelpers.assertDuration(args[1], -43, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Second argument"); + assert.sameValue(typeof args[2], "object", "Third argument: type"); + assert.sameValue(Object.getPrototypeOf(args[2]), null, "Third argument: prototype"); + assert.compareArray(Object.keys(args[2]), [], "Third argument: keys"); + return result; + } +} +const calendar = new CustomCalendar(); +const plainDate = new Temporal.PlainDate(1976, 11, 18, calendar); +assert.sameValue(plainDate.subtract({ years: 43 }), result); +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..be3aed422b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/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.PlainDate.prototype.subtract throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plaindate.prototype.subtract +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); + +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/PlainDate/prototype/subtract/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/length.js new file mode 100644 index 0000000000..e430147b69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Temporal.PlainDate.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.PlainDate.prototype.subtract, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/limits.js new file mode 100644 index 0000000000..ec4378ed8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/limits.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. + +/*--- +description: Temporal.PlainDate.prototype.subtract throws a RangeError if the calculation crosses a limit +esid: sec-temporal.plaindate.prototype.subtract +features: [Temporal] +---*/ + +const min = Temporal.PlainDate.from("-271821-04-19"); +const max = Temporal.PlainDate.from("+275760-09-13"); +["reject", "constrain"].forEach((overflow) => { + assert.throws(RangeError, () => min.subtract({ days: 1 }, { overflow }), `min with ${overflow}`); + assert.throws(RangeError, () => max.subtract({ days: -1 }, { overflow }), `max with ${overflow}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/name.js new file mode 100644 index 0000000000..59ca6ea774 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Temporal.PlainDate.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.PlainDate.prototype.subtract, "name", { + value: "subtract", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..7f67ed0839 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.PlainDate.prototype.subtract throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plaindate.prototype.subtract +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 }); + +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/PlainDate/prototype/subtract/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..a6a93fbf73 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/subtract/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/not-a-constructor.js new file mode 100644 index 0000000000..47123f35d1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: > + Temporal.PlainDate.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.PlainDate.prototype.subtract(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.subtract), false, + "isConstructor(Temporal.PlainDate.prototype.subtract)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-object.js new file mode 100644 index 0000000000..e365c0edd0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.subtract({ months: 1 }, {}); +TemporalHelpers.assertPlainDate( + result1, 2000, 4, "M04", 2, + "options may be an empty plain object" +); + +const result2 = instance.subtract({ months: 1 }, () => {}); +TemporalHelpers.assertPlainDate( + result2, 2000, 4, "M04", 2, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-undefined.js new file mode 100644 index 0000000000..ecc573fe5b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-undefined.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.plaindate.prototype.subtract +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 3, 31); +const duration = { months: 1 }; + +const explicit = date.subtract(duration, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = date.subtract(duration); +assert.sameValue(implicit.month, 2, "default overflow is constrain"); +assert.sameValue(implicit.day, 29, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/options-wrong-type.js new file mode 100644 index 0000000000..ae2d8a5e1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/order-of-operations.js new file mode 100644 index 0000000000..b3bcb378aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/order-of-operations.js @@ -0,0 +1,129 @@ +// |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.plaindate.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 = [ + // ToTemporalDurationRecord + "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", + // AddDate + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + // inside Calendar.p.dateAdd + "get options.overflow", + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, 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 = [ + // ToTemporalDurationRecord + "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", + "get this.calendar.dateAdd", + // AddDate + "get options.overflow", + "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 operation"); + +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-constrain.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-constrain.js new file mode 100644 index 0000000000..b95f00c8a6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-constrain.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.plaindate.prototype.subtract +description: Constrains with overflow constrain +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const mar31 = Temporal.PlainDate.from("2020-03-31"); +TemporalHelpers.assertPlainDate(mar31.subtract({ months: 1 }, { overflow: "constrain" }), + 2020, 2, "M02", 29); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.js new file mode 100644 index 0000000000..625e8b02be --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-invalid-string.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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.subtract step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _negatedDuration_, _options_). +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(3, 3, 0, 3); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.subtract(duration, { overflow }), + `invalid overflow ("${overflow}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-reject.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-reject.js new file mode 100644 index 0000000000..e64d34f8ab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/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.plaindate.prototype.subtract +description: Throws with overflow reject +features: [Temporal] +---*/ + +const mar31 = Temporal.PlainDate.from("2020-03-31"); +assert.throws(RangeError, () => mar31.subtract({ months: 1 }, { overflow: "reject" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-undefined.js new file mode 100644 index 0000000000..ae5caf3df9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-undefined.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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.subtract step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _negatedDuration_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 31); +const duration = new Temporal.Duration(3, 1); + +const explicit = date.subtract(duration, { overflow: undefined }); +TemporalHelpers.assertPlainDate(explicit, 1997, 4, "M04", 30, "default overflow is constrain"); +const implicit = date.subtract(duration, {}); +TemporalHelpers.assertPlainDate(implicit, 1997, 4, "M04", 30, "default overflow is constrain"); +const lambda = date.subtract(duration, {}); +TemporalHelpers.assertPlainDate(lambda, 1997, 4, "M04", 30, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-wrong-type.js new file mode 100644 index 0000000000..fc1222b4f4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/overflow-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.plaindate.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.calendar.prototype.dateadd step 7: + 7. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.subtract step 7: + 7. Return ? CalendarDateAdd(_temporalDate_.[[Calendar]], _temporalDate_, _negatedDuration_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const duration = new Temporal.Duration(3, 3, 0, 3); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => date.subtract(duration, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDate(result, 1997, 1, "M01", 30, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/prop-desc.js new file mode 100644 index 0000000000..8cf73cfc43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/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.plaindate.prototype.subtract +description: The "subtract" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.subtract, + "function", + "`typeof PlainDate.prototype.subtract` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "subtract", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/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/PlainDate/prototype/subtract/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/subclassing-ignored.js new file mode 100644 index 0000000000..70dcbfaa75 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.subtract +description: Objects of a subclass are never created as return values for subtract() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDate, + [2000, 5, 2], + "subtract", + [{ days: 1 }], + (result) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 1), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/basic.js new file mode 100644 index 0000000000..b81332353d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/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.plaindate.prototype.tojson +description: Basic behavior for toJSON +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDate(1976, 2, 4), "1976-02-04"], + [new Temporal.PlainDate(1976, 11, 18), "1976-11-18"], +]; + +const options = new Proxy({}, { + get() { throw new Test262Error("should not get properties off argument") } +}); +for (const [datetime, expected] of tests) { + assert.sameValue(datetime.toJSON(), expected, "toJSON without argument"); + assert.sameValue(datetime.toJSON(options), expected, "toJSON with argument"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/branding.js new file mode 100644 index 0000000000..74cd8d11a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/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.plaindate.prototype.tojson +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toJSON = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toJSON.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..967f21f909 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.toJSON(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/builtin.js new file mode 100644 index 0000000000..24e1001083 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tojson +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.toJSON), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toJSON), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toJSON), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toJSON.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/length.js new file mode 100644 index 0000000000..dd1d659d44 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tojson +description: Temporal.PlainDate.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.PlainDate.prototype.toJSON, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/name.js new file mode 100644 index 0000000000..e60424bd10 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tojson +description: Temporal.PlainDate.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.PlainDate.prototype.toJSON, "name", { + value: "toJSON", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/not-a-constructor.js new file mode 100644 index 0000000000..53116ce170 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tojson +description: > + Temporal.PlainDate.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.PlainDate.prototype.toJSON(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toJSON), false, + "isConstructor(Temporal.PlainDate.prototype.toJSON)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/prop-desc.js new file mode 100644 index 0000000000..ba879c3a2a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/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.plaindate.prototype.tojson +description: The "toJSON" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toJSON, + "function", + "`typeof PlainDate.prototype.toJSON` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toJSON", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/toJSON/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toJSON/year-format.js new file mode 100644 index 0000000000..4d2d63938d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDate(-100000, 12, 3); +assert.sameValue(instance.toJSON(), "-100000-12-03", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-10000, 4, 5); +assert.sameValue(instance.toJSON(), "-010000-04-05", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-9999, 6, 7); +assert.sameValue(instance.toJSON(), "-009999-06-07", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1000, 8, 9); +assert.sameValue(instance.toJSON(), "-001000-08-09", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-999, 10, 9); +assert.sameValue(instance.toJSON(), "-000999-10-09", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1, 8, 7); +assert.sameValue(instance.toJSON(), "-000001-08-07", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDate(0, 6, 5); +assert.sameValue(instance.toJSON(), "0000-06-05", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDate(1, 4, 3); +assert.sameValue(instance.toJSON(), "0001-04-03", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDate(999, 2, 10); +assert.sameValue(instance.toJSON(), "0999-02-10", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(1000, 1, 23); +assert.sameValue(instance.toJSON(), "1000-01-23", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(9999, 4, 5); +assert.sameValue(instance.toJSON(), "9999-04-05", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(10000, 6, 7); +assert.sameValue(instance.toJSON(), "+010000-06-07", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDate(100000, 8, 9); +assert.sameValue(instance.toJSON(), "+100000-08-09", "large positive year formatted as 6-digit"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/branding.js new file mode 100644 index 0000000000..11881e250e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/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.plaindate.prototype.tolocalestring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toLocaleString = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toLocaleString.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..990b1c7470 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.toLocaleString(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/builtin.js new file mode 100644 index 0000000000..0d5e2c8308 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tolocalestring +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.toLocaleString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toLocaleString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toLocaleString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toLocaleString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/length.js new file mode 100644 index 0000000000..560284d39a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tolocalestring +description: Temporal.PlainDate.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.PlainDate.prototype.toLocaleString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/name.js new file mode 100644 index 0000000000..3c37d8082f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tolocalestring +description: Temporal.PlainDate.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.PlainDate.prototype.toLocaleString, "name", { + value: "toLocaleString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/not-a-constructor.js new file mode 100644 index 0000000000..0e2ff764d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tolocalestring +description: > + Temporal.PlainDate.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.PlainDate.prototype.toLocaleString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toLocaleString), false, + "isConstructor(Temporal.PlainDate.prototype.toLocaleString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/prop-desc.js new file mode 100644 index 0000000000..ae8d974087 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/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.plaindate.prototype.tolocalestring +description: The "toLocaleString" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toLocaleString, + "function", + "`typeof PlainDate.prototype.toLocaleString` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toLocaleString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js new file mode 100644 index 0000000000..3843752842 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Kate Miháliková. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.tolocalestring +description: > + toLocaleString return a string. +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); + +assert.sameValue(typeof date.toLocaleString("en", { dateStyle: "short" }), "string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toLocaleString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/toPlainDateTime/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-number.js new file mode 100644 index 0000000000..8c0d46c48f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: A number is invalid in place of an ISO string for Temporal.PlainTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const numbers = [ + 1, + -123456.987654321, + 1234567, + 123456.9876543219, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.toPlainDateTime(arg), + `A number (${arg}) is not a valid ISO string for PlainTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-object.js new file mode 100644 index 0000000000..950b2b0e49 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-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.plaindate.prototype.toplaindatetime +description: Tests for toPlainDateTime() with an object argument. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(2000, 5, 2); +const calendar = { toString() { return "iso8601" } }; +const withOverflow = plainDate.toPlainDateTime({ hour: 25, minute: 70, second: 23 }); +TemporalHelpers.assertPlainDateTime(withOverflow, 2000, 5, "M05", 2, 23, 59, 23, 0, 0, 0, "with overflow"); +assert.sameValue(withOverflow.calendar, plainDate.calendar, "with overflow calendar"); + +const withCalendar = plainDate.toPlainDateTime({ hour: 13, calendar }); +TemporalHelpers.assertPlainDateTime(withCalendar, 2000, 5, "M05", 2, 13, 0, 0, 0, 0, 0, "with calendar"); +assert.sameValue(withCalendar.calendar, plainDate.calendar, "with calendar calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..7b7b86161b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-calendar-annotation.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.plaindate.prototype.toplaindatetime +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["12:34:56.987654321[u-ca=iso8601]", "without time zone"], + ["12:34:56.987654321[UTC][u-ca=iso8601]", "with time zone"], + ["12:34:56.987654321[!u-ca=iso8601]", "with ! and no time zone"], + ["12:34:56.987654321[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["T12:34:56.987654321[u-ca=iso8601]", "with T and no time zone"], + ["T12:34:56.987654321[UTC][u-ca=iso8601]", "with T and time zone"], + ["T12:34:56.987654321[!u-ca=iso8601]", "with T, !, and no time zone"], + ["T12:34:56.987654321[UTC][!u-ca=iso8601]", "with T, !, and time zone"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601]", "with date and no time zone"], + ["1970-01-01T12:34:56.987654321[UTC][u-ca=iso8601]", "with date and time zone"], + ["1970-01-01T12:34:56.987654321[!u-ca=iso8601]", "with !, date, and no time zone"], + ["1970-01-01T12:34:56.987654321[UTC][!u-ca=iso8601]", "with !, date, and time zone"], + ["12:34:56.987654321[u-ca=hebrew]", "calendar annotation ignored"], + ["12:34:56.987654321[u-ca=unknown]", "calendar annotation ignored even if unknown calendar"], + ["12:34:56.987654321[!u-ca=unknown]", "calendar annotation ignored even if unknown calendar with !"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toPlainDateTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..7c3603fb69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-critical-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.plaindate.prototype.toplaindatetime +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[!foo=bar]", + "T00:00[!foo=bar]", + "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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..a9af6a6da0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-date-with-utc-offset.js @@ -0,0 +1,53 @@ +// |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.plaindate.prototype.toplaindatetime +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const validStrings = [ + "12:34:56.987654321+00:00", + "12:34:56.987654321+00:00[UTC]", + "12:34:56.987654321+00:00[!UTC]", + "12:34:56.987654321-02:30[America/St_Johns]", + "1976-11-18T12:34:56.987654321+00:00", + "1976-11-18T12:34:56.987654321+00:00[UTC]", + "1976-11-18T12:34:56.987654321+00:00[!UTC]", + "1976-11-18T12:34:56.987654321-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = instance.toPlainDateTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + `"${arg}" is a valid UTC offset with time for PlainTime` + ); +} + +const invalidStrings = [ + "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.toPlainDateTime(arg), + `"${arg}" UTC offset without time is not valid for PlainTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..320c02eb57 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[u-ca=iso8601][!u-ca=iso8601]", + "00:00[!u-ca=iso8601][u-ca=iso8601]", + "00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "00:00[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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..ab6b4d7001 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-multiple-time-zone.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.plaindate.prototype.toplaindatetime +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[UTC][UTC]", + "T00:00[UTC][UTC]", + "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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-no-implicit-midnight.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-no-implicit-midnight.js new file mode 100644 index 0000000000..b07a0fe3a6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-no-implicit-midnight.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.plaindate.prototype.toplaindatetime +description: RangeError thrown if a date-only string is passed in a PlainTime context +features: [Temporal, arrow-function] +---*/ + +const arg = "2019-10-01"; +const instance = new Temporal.PlainDate(2000, 5, 2); +assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + "Date-only string throws, does not implicitly convert to midnight" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-designator-required-for-disambiguation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-designator-required-for-disambiguation.js new file mode 100644 index 0000000000..eaecbfeb56 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-designator-required-for-disambiguation.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.plaindate.prototype.toplaindatetime +description: ISO 8601 time designator "T" required in cases of ambiguity +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +TemporalHelpers.ISO.plainTimeStringsAmbiguous().forEach((string) => { + let arg = string; + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `'${arg}' is ambiguous and requires T prefix` + ); + // The same string with a T prefix should not throw: + arg = `T${string}`; + instance.toPlainDateTime(arg); + + arg = ` ${string}`; + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + `space is not accepted as a substitute for T prefix: '${arg}'` + ); +}); + +// None of these should throw without a T prefix, because they are unambiguously time strings: +TemporalHelpers.ISO.plainTimeStringsUnambiguous().forEach( + (arg) => instance.toPlainDateTime(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-separators.js new file mode 100644 index 0000000000..6819a99c6c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T12:34:56.987654321", "uppercase T"], + ["1976-11-18t12:34:56.987654321", "lowercase T"], + ["1976-11-18 12:34:56.987654321", "space between date and time"], + ["T12:34:56.987654321", "time-only uppercase T"], + ["t12:34:56.987654321", "time-only lowercase T"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toPlainDateTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..fea520d08d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-zone-annotation.js @@ -0,0 +1,51 @@ +// |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.plaindate.prototype.toplaindatetime +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["12:34:56.987654321[Asia/Kolkata]", "named, with no offset"], + ["12:34:56.987654321[!Europe/Vienna]", "named, with ! and no offset"], + ["12:34:56.987654321[+00:00]", "numeric, with no offset"], + ["12:34:56.987654321[!-02:30]", "numeric, with ! and no offset"], + ["T12:34:56.987654321[UTC]", "named, with T and no offset"], + ["T12:34:56.987654321[!Africa/Abidjan]", "named, with T, !, and no offset"], + ["T12:34:56.987654321[+01:00]", "numeric, with T and no offset"], + ["T12:34:56.987654321[!-08:00]", "numeric, with T, !, and no offset"], + ["12:34:56.987654321+00:00[America/Sao_Paulo]", "named, with offset"], + ["12:34:56.987654321+00:00[!Asia/Tokyo]", "named, with ! and offset"], + ["12:34:56.987654321+00:00[-02:30]", "numeric, with offset"], + ["12:34:56.987654321+00:00[!+00:00]", "numeric, with ! and offset"], + ["T12:34:56.987654321+00:00[America/New_York]", "named, with T and offset"], + ["T12:34:56.987654321+00:00[!UTC]", "named, with T, !, and offset"], + ["T12:34:56.987654321+00:00[-08:00]", "numeric, with T and offset"], + ["T12:34:56.987654321+00:00[!+01:00]", "numeric, with T, !, and offset"], + ["1970-01-01T12:34:56.987654321[Africa/Lagos]", "named, with date and no offset"], + ["1970-01-01T12:34:56.987654321[!America/Vancouver]", "named, with date, !, and no offset"], + ["1970-01-01T12:34:56.987654321[+00:00]", "numeric, with date and no offset"], + ["1970-01-01T12:34:56.987654321[!-02:30]", "numeric, with date, !, and no offset"], + ["1970-01-01T12:34:56.987654321+00:00[Europe/London]", "named, with date and offset"], + ["1970-01-01T12:34:56.987654321+00:00[!Asia/Seoul]", "named, with date, offset, and !"], + ["1970-01-01T12:34:56.987654321+00:00[+01:00]", "numeric, with date and offset"], + ["1970-01-01T12:34:56.987654321+00:00[!-08:00]", "numeric, with date, offset, and !"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toPlainDateTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..229b3c496a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-unknown-annotation.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.plaindate.prototype.toplaindatetime +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["12:34:56.987654321[foo=bar]", "alone"], + ["12:34:56.987654321[UTC][foo=bar]", "with time zone"], + ["12:34:56.987654321[u-ca=iso8601][foo=bar]", "with calendar"], + ["12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["T12:34:56.987654321[foo=bar]", "with T"], + ["T12:34:56.987654321[UTC][foo=bar]", "with T and time zone"], + ["T12:34:56.987654321[u-ca=iso8601][foo=bar]", "with T and calendar"], + ["T12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with T, time zone, and calendar"], + ["1970-01-01T12:34:56.987654321[foo=bar]", "with date"], + ["1970-01-01T12:34:56.987654321[UTC][foo=bar]", "with date and time zone"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601][foo=bar]", "with date and calendar"], + ["1970-01-01T12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with date, time zone, and calendar"], + ["1970-01-01T12:34:56.987654321[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toPlainDateTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-time-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-time-designator.js new file mode 100644 index 0000000000..b4911b666e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-time-designator.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.plaindate.prototype.toplaindatetime +description: ISO 8601 time designator "T" allowed at the start of PlainTime strings +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDate(2000, 1, 1); +const validStrings = [ + "T00:30", + "t00:30", + "T0030", + "t0030", + "T00:30:00", + "t00:30:00", + "T003000", + "t003000", + "T00:30:00.000000000", + "t00:30:00.000000000", + "T003000.000000000", + "t003000.000000000", +]; +validStrings.forEach((arg) => { + const result = instance.toPlainDateTime(arg); + TemporalHelpers.assertPlainDateTime(result, 2000, 1, "M01", 1, 0, 30, 0, 0, 0, 0, `T prefix is accepted: ${arg}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..889739cf59 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-with-utc-designator.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.plaindate.prototype.toplaindatetime +description: RangeError thrown if a string with UTC designator is used as a PlainTime +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", + "09:00:00Z[UTC]", + "09:00:00Z", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + "String with UTC designator should not be valid as a PlainTime" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-wrong-type.js new file mode 100644 index 0000000000..9debfc601d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-wrong-type.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.toplaindatetime +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainTime +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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, + () => instance.toPlainDateTime(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainTime, "Temporal.PlainTime, object"], + [Temporal.PlainTime.prototype, "Temporal.PlainTime.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.toPlainDateTime(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/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..964d7d6c68 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-balance-negative-time-units.js @@ -0,0 +1,47 @@ +// |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.plaindate.prototype.toplaindatetime +description: Negative time fields are balanced upwards if the argument is given as ZonedDateTime +info: | + sec-temporal-balancetime steps 3–14: + 3. Set _microsecond_ to _microsecond_ + floor(_nanosecond_ / 1000). + 4. Set _nanosecond_ to _nanosecond_ modulo 1000. + 5. Set _millisecond_ to _millisecond_ + floor(_microsecond_ / 1000). + 6. Set _microsecond_ to _microsecond_ modulo 1000. + 7. Set _second_ to _second_ + floor(_millisecond_ / 1000). + 8. Set _millisecond_ to _millisecond_ modulo 1000. + 9. Set _minute_ to _minute_ + floor(_second_ / 60). + 10. Set _second_ to _second_ modulo 60. + 11. Set _hour_ to _hour_ + floor(_minute_ / 60). + 12. Set _minute_ to _minute_ modulo 60. + 13. Let _days_ be floor(_hour_ / 24). + 14. Set _hour_ to _hour_ modulo 24. + sec-temporal-balanceisodatetime step 1: + 1. Let _balancedTime_ be ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_). + sec-temporal-builtintimezonegetplaindatetimefor step 3: + 3. Set _result_ to ? BalanceISODateTime(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]] + _offsetNanoseconds_). + sec-temporal-totemporaltime step 3.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + ... + ii. 1. Set _plainDateTime_ to ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). + sec-temporal.plaindate.prototype.toplaindatetime step 4: + 4. Set _temporalTime_ to ? ToTemporalTime(_temporalTime_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// This code path is encountered if the time zone offset is negative and its +// absolute value in nanoseconds is greater than the nanosecond field of the +// exact time's epoch parts +const tz = TemporalHelpers.specificOffsetTimeZone(-2); +const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz); + +const date = new Temporal.PlainDate(2000, 5, 2); +const pdt = date.toPlainDateTime(datetime); + +TemporalHelpers.assertPlainDateTime(pdt, 2000, 5, "M05", 2, 1, 1, 1, 1, 0, 999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..19fb21bc72 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-negative-epochnanoseconds.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.plaindate.prototype.toplaindatetime +description: A pre-epoch value is handled correctly by the modulo operation in GetISOPartsFromEpoch +info: | + sec-temporal-getisopartsfromepoch step 1: + 1. Let _remainderNs_ be the mathematical value whose sign is the sign of _epochNanoseconds_ and whose magnitude is abs(_epochNanoseconds_) modulo 10<sup>6</sup>. + sec-temporal-builtintimezonegetplaindatetimefor step 2: + 2. Let _result_ be ! GetISOPartsFromEpoch(_instant_.[[Nanoseconds]]). +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const datetime = new Temporal.ZonedDateTime(-13849764_999_999_999n, "UTC"); + +// This code path shows up anywhere we convert an exact time, before the Unix +// epoch, with nonzero microseconds or nanoseconds, into a wall time. + +const instance = new Temporal.PlainDate(2000, 5, 2); +const result = instance.toPlainDateTime(datetime); +TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 16, 50, 35, 0, 0, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..e969e0d72d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.toplaindatetime +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.toPlainDateTime(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..350e9e3644 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.toplaindatetime +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.toPlainDateTime(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..8145f3160e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.toplaindatetime +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.toPlainDateTime(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..32fcf358d6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.prototype.toplaindatetime +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => date.toPlainDateTime(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/basic.js new file mode 100644 index 0000000000..ee3f828471 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/basic.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.plaindate.prototype.toplaindatetime +description: Basic tests for toPlainDateTime(). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); + +const string = date.toPlainDateTime("11:30:23"); +TemporalHelpers.assertPlainDateTime(string, 2000, 5, "M05", 2, 11, 30, 23, 0, 0, 0, "string"); +assert.sameValue(string.calendar, date.calendar, "string calendar"); + +const optionBag = date.toPlainDateTime({ hour: 11, minute: 30, second: 23 }); +TemporalHelpers.assertPlainDateTime(optionBag, 2000, 5, "M05", 2, 11, 30, 23, 0, 0, 0, "option bag"); +assert.sameValue(optionBag.calendar, date.calendar, "option bag calendar"); + +const plainTime = date.toPlainDateTime(Temporal.PlainTime.from("11:30:23")); +TemporalHelpers.assertPlainDateTime(plainTime, 2000, 5, "M05", 2, 11, 30, 23, 0, 0, 0, "PlainTime"); +assert.sameValue(plainTime.calendar, date.calendar, "PlainTime calendar"); + +const plainDateTime = date.toPlainDateTime(Temporal.PlainDateTime.from("1999-07-14T11:30:23")); +TemporalHelpers.assertPlainDateTime(plainDateTime, 2000, 5, "M05", 2, 11, 30, 23, 0, 0, 0, "PlainDateTime"); +assert.sameValue(plainDateTime.calendar, date.calendar, "PlainDateTime calendar"); + +const zonedDateTime = date.toPlainDateTime(Temporal.ZonedDateTime.from("1999-07-14T11:30:23Z[UTC]")); +TemporalHelpers.assertPlainDateTime(zonedDateTime, 2000, 5, "M05", 2, 11, 30, 23, 0, 0, 0, "ZonedDateTime"); +assert.sameValue(zonedDateTime.calendar, date.calendar, "ZonedDateTime calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/branding.js new file mode 100644 index 0000000000..4e05ce4608 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainDateTime = Temporal.PlainDate.prototype.toPlainDateTime; + +assert.sameValue(typeof toPlainDateTime, "function"); + +assert.throws(TypeError, () => toPlainDateTime.call(undefined), "undefined"); +assert.throws(TypeError, () => toPlainDateTime.call(null), "null"); +assert.throws(TypeError, () => toPlainDateTime.call(true), "true"); +assert.throws(TypeError, () => toPlainDateTime.call(""), "empty string"); +assert.throws(TypeError, () => toPlainDateTime.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toPlainDateTime.call(1), "1"); +assert.throws(TypeError, () => toPlainDateTime.call({}), "plain object"); +assert.throws(TypeError, () => toPlainDateTime.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toPlainDateTime.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/builtin.js new file mode 100644 index 0000000000..e3a19cdf87 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: > + Tests that Temporal.PlainDate.prototype.toPlainDateTime + 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.PlainDate.prototype.toPlainDateTime), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toPlainDateTime), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toPlainDateTime), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toPlainDateTime.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/custom.js new file mode 100644 index 0000000000..feecd145ab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/custom.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.plaindate.prototype.toplaindatetime +description: toPlainDateTime() doesn't call into the calendar. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarThrowEverything(); +const plainDate = new Temporal.PlainDate(2000, 5, 2, calendar); +const result = plainDate.toPlainDateTime("11:30:23"); +assert.sameValue(result.getCalendar(), calendar, "calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/leap-second.js new file mode 100644 index 0000000000..0e51120afe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: Leap second is a valid ISO string for PlainTime +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.toPlainDateTime(arg); +TemporalHelpers.assertPlainDateTime( + result1, + 2000, 5, "M05", 2, 23, 59, 59, 0, 0, 0, + "leap second is a valid ISO string for PlainTime" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +const result2 = instance.toPlainDateTime(arg); +TemporalHelpers.assertPlainDateTime( + result2, + 2000, 5, "M05", 2, 23, 59, 59, 0, 0, 0, + "second: 60 is ignored in property bag for PlainTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/length.js new file mode 100644 index 0000000000..b379b4487f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: Temporal.PlainDate.prototype.toPlainDateTime.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.PlainDate.prototype.toPlainDateTime, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/limits.js new file mode 100644 index 0000000000..ef00cbc673 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/limits.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.toplaindatetime +description: Checking limits of representable PlainDateTime +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const midnight = new Temporal.PlainTime(0, 0); +const firstNs = new Temporal.PlainTime(0, 0, 0, 0, 0, 1); +const lastNs = new Temporal.PlainTime(23, 59, 59, 999, 999, 999); +const min = new Temporal.PlainDate(-271821, 4, 19); +const max = new Temporal.PlainDate(275760, 9, 13); + +assert.throws( + RangeError, + () => min.toPlainDateTime(midnight), + "Cannot go below representable limit for PlainDateTime" +); + +TemporalHelpers.assertPlainDateTime( + max.toPlainDateTime(midnight), + 275760, 9, "M09", 13, 0, 0, 0, 0, 0, 0, + "Midnight on maximal representable PlainDate" +); + +TemporalHelpers.assertPlainDateTime( + min.toPlainDateTime(firstNs), + -271821, 4, "M04", 19, 0, 0, 0, 0, 0, 1, + "Computing the minimum (earliest) representable PlainDateTime" +); + +TemporalHelpers.assertPlainDateTime( + max.toPlainDateTime(lastNs), + 275760, 9, "M09", 13, 23, 59, 59, 999, 999, 999, + "Computing the maximum (latest) representable PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/name.js new file mode 100644 index 0000000000..6602a260cc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: Temporal.PlainDate.prototype.toPlainDateTime.name is "toPlainDateTime". +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.PlainDate.prototype.toPlainDateTime, "name", { + value: "toPlainDateTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/not-a-constructor.js new file mode 100644 index 0000000000..1c7ef2a91e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: > + Temporal.PlainDate.prototype.toPlainDateTime 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.PlainDate.prototype.toPlainDateTime(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toPlainDateTime), false, + "isConstructor(Temporal.PlainDate.prototype.toPlainDateTime)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/plaintime-propertybag-no-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/plaintime-propertybag-no-time-units.js new file mode 100644 index 0000000000..0c2dc3a98e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/plaintime-propertybag-no-time-units.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.plaindate.prototype.toplaindatetime +description: Missing time units in property bag default to 0 +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 1, 1); + +const props = {}; +assert.throws(TypeError, () => instance.toPlainDateTime(props), "TypeError if no properties are present"); + +props.minute = 30; +const result = instance.toPlainDateTime(props); +TemporalHelpers.assertPlainDateTime(result, 2000, 1, "M01", 1, 0, 30, 0, 0, 0, 0, "missing time units default to 0"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/prop-desc.js new file mode 100644 index 0000000000..4d1804f704 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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.plaindate.prototype.toplaindatetime +description: The "toPlainDateTime" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toPlainDateTime, + "function", + "`typeof PlainDate.prototype.toPlainDateTime` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toPlainDateTime", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/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/PlainDate/prototype/toPlainDateTime/time-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/time-invalid.js new file mode 100644 index 0000000000..410d715a42 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/time-invalid.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.plaindate.prototype.toplaindatetime +description: TypeError thrown if an invalid property bag passed +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(2000, 5, 2); +assert.throws(TypeError, () => plainDate.toPlainDateTime({}), "empty object"); +assert.throws(TypeError, () => plainDate.toPlainDateTime({ minutes: 30 }), "plural property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/time-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/time-undefined.js new file mode 100644 index 0000000000..19b2c1148a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/time-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.plaindate.prototype.toplaindatetime +description: The time is assumed to be midnight if not given +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); + +const explicit = date.toPlainDateTime(undefined); +TemporalHelpers.assertPlainDateTime(explicit, 2000, 5, "M05", 2, 0, 0, 0, 0, 0, 0, "default time is midnight - explicit"); + +const implicit = date.toPlainDateTime(); +TemporalHelpers.assertPlainDateTime(implicit, 2000, 5, "M05", 2, 0, 0, 0, 0, 0, 0, "default time is midnight - implicit"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/year-zero.js new file mode 100644 index 0000000000..d91e610a16 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainDateTime/year-zero.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.plaindate.prototype.toplaindatetime +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-12-07T03:24:30", + "-000000-12-07T03:24:30+01:00", + "-000000-12-07T03:24:30+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toPlainDateTime(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/basic.js new file mode 100644 index 0000000000..8913418dd4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: Basic toPlainMonthDay tests. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const pd = new Temporal.PlainDate(1970, 12, 24, calendar); +const pmd = pd.toPlainMonthDay(); +TemporalHelpers.assertPlainMonthDay(pmd, "M12", 24); +assert.sameValue(pmd.getISOFields().calendar, "iso8601"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/branding.js new file mode 100644 index 0000000000..7e8ac4ce94 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainMonthDay = Temporal.PlainDate.prototype.toPlainMonthDay; + +assert.sameValue(typeof toPlainMonthDay, "function"); + +assert.throws(TypeError, () => toPlainMonthDay.call(undefined), "undefined"); +assert.throws(TypeError, () => toPlainMonthDay.call(null), "null"); +assert.throws(TypeError, () => toPlainMonthDay.call(true), "true"); +assert.throws(TypeError, () => toPlainMonthDay.call(""), "empty string"); +assert.throws(TypeError, () => toPlainMonthDay.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toPlainMonthDay.call(1), "1"); +assert.throws(TypeError, () => toPlainMonthDay.call({}), "plain object"); +assert.throws(TypeError, () => toPlainMonthDay.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toPlainMonthDay.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..b6551cc78e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +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.PlainDate(2023, 5, 2, "iso8601"); +instance.toPlainMonthDay(); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..415b89e0c6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +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 monthDayFromFieldsOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "monthDayFromFields"); +Object.defineProperty(Temporal.Calendar.prototype, "monthDayFromFields", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("monthDayFromFields should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.toPlainMonthDay(); + +Object.defineProperty(Temporal.Calendar.prototype, "monthDayFromFields", monthDayFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/builtin.js new file mode 100644 index 0000000000..1c6fce388a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: > + Tests that Temporal.PlainDate.prototype.toPlainMonthDay + 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.PlainDate.prototype.toPlainMonthDay), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toPlainMonthDay), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toPlainMonthDay), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toPlainMonthDay.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-arguments.js new file mode 100644 index 0000000000..0c4cec8683 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-arguments.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.plaindate.prototype.toplainmonthday +description: Correct options value is passed to calendar method +info: | + MonthDayFromFields ( calendar, fields [ , options ] ) + + 3. If options is not present, then + a. Set options to undefined. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + monthDayFromFields(...args) { + assert.sameValue(args.length, 2, "args.length"); + assert.sameValue(typeof args[0], "object", "args[0]"); + assert.sameValue(args[1], undefined, "args[1]"); + return super.monthDayFromFields(...args); + } +} +const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar()); +const result = plainDate.toPlainMonthDay(); +TemporalHelpers.assertPlainMonthDay(result, "M05", 2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js new file mode 100644 index 0000000000..04a6061fe0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.toplainmonthday step 4: + 4. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"monthCode"* »). + sec-temporal-calendarfields step 4: + 4. Let _result_ be ? IterableToList(_fieldsArray_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "day", + "monthCode", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const date = new Temporal.PlainDate(2000, 5, 2, calendar); +date.toPlainMonthDay(); + +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/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..ed596ad4a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with a null-prototype fields object +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1, "monthDayFromFields should have been called on the calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-invalid-return.js new file mode 100644 index 0000000000..8bab7f5cdf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-invalid-return.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.toplainmonthday +description: Throw when the returned value is not a PlainMonthDay. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + monthDayFromFields() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.PlainMonthDay, "Temporal.PlainMonthDay"], + [Temporal.PlainMonthDay.prototype, "Temporal.PlainMonthDay.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws(TypeError, () => plainDate.toPlainMonthDay(), `Expected error with ${description}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..2c1fbc5862 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-monthdayfromfields-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.plaindate.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..1151eadc13 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.toPlainMonthDay()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/duplicate-calendar-fields.js new file mode 100644 index 0000000000..3467871850 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +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'], ['day']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const date = new Temporal.PlainDate(2023, 5, 1, calendar); + + assert.throws(RangeError, () => date.toPlainMonthDay()); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/length.js new file mode 100644 index 0000000000..e86efba232 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: Temporal.PlainDate.prototype.toPlainMonthDay.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.PlainDate.prototype.toPlainMonthDay, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/name.js new file mode 100644 index 0000000000..6df4fb2d10 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: Temporal.PlainDate.prototype.toPlainMonthDay.name is "toPlainMonthDay". +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.PlainDate.prototype.toPlainMonthDay, "name", { + value: "toPlainMonthDay", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/not-a-constructor.js new file mode 100644 index 0000000000..0c64846eef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: > + Temporal.PlainDate.prototype.toPlainMonthDay 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.PlainDate.prototype.toPlainMonthDay(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toPlainMonthDay), false, + "isConstructor(Temporal.PlainDate.prototype.toPlainMonthDay)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/prop-desc.js new file mode 100644 index 0000000000..e6d11cf65c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +description: The "toPlainMonthDay" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toPlainMonthDay, + "function", + "`typeof PlainDate.prototype.toPlainMonthDay` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toPlainMonthDay", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/proto-in-calendar-fields.js new file mode 100644 index 0000000000..d77d73bef1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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.plaindate.prototype.toplainmonthday +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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.toPlainMonthDay()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/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/PlainDate/prototype/toPlainYearMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/basic.js new file mode 100644 index 0000000000..f0375df0d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: Basic toPlainYearMonth tests. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const pd = new Temporal.PlainDate(1970, 12, 24, calendar); +const pym = pd.toPlainYearMonth(); +TemporalHelpers.assertPlainYearMonth(pym, 1970, 12, "M12"); +assert.sameValue(pym.getISOFields().calendar, "iso8601"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/branding.js new file mode 100644 index 0000000000..474a20edae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainYearMonth = Temporal.PlainDate.prototype.toPlainYearMonth; + +assert.sameValue(typeof toPlainYearMonth, "function"); + +assert.throws(TypeError, () => toPlainYearMonth.call(undefined), "undefined"); +assert.throws(TypeError, () => toPlainYearMonth.call(null), "null"); +assert.throws(TypeError, () => toPlainYearMonth.call(true), "true"); +assert.throws(TypeError, () => toPlainYearMonth.call(""), "empty string"); +assert.throws(TypeError, () => toPlainYearMonth.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toPlainYearMonth.call(1), "1"); +assert.throws(TypeError, () => toPlainYearMonth.call({}), "plain object"); +assert.throws(TypeError, () => toPlainYearMonth.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toPlainYearMonth.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..120d0e59a4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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.PlainDate(2023, 5, 2, "iso8601"); +instance.toPlainYearMonth(); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..1254551e64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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 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.PlainDate(2000, 5, 2, "iso8601"); +instance.toPlainYearMonth(); + +Object.defineProperty(Temporal.Calendar.prototype, "yearMonthFromFields", yearMonthFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/builtin.js new file mode 100644 index 0000000000..2aaa7857cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: > + Tests that Temporal.PlainDate.prototype.toPlainYearMonth + 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.PlainDate.prototype.toPlainYearMonth), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toPlainYearMonth), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toPlainYearMonth), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toPlainYearMonth.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-arguments.js new file mode 100644 index 0000000000..af062b81de --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-arguments.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.plaindate.prototype.toplainyearmonth +description: Correct options value is passed to calendar method +info: | + YearMonthFromFields ( calendar, fields [ , options ] ) + + 3. If options is not present, then + a. Set options to undefined. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +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.sameValue(args[1], undefined, "args[1]"); + return super.yearMonthFromFields(...args); + } +} +const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar()); +const result = plainDate.toPlainYearMonth(); +TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fields-iterable.js new file mode 100644 index 0000000000..60d60b3ba5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.toplainyearmonth step 4: + 4. 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 date = new Temporal.PlainDate(2000, 5, 2, calendar); +date.toPlainYearMonth(); + +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/PlainDate/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..c22c2e0f28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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.PlainDate(2000, 5, 2, calendar); +instance.toPlainYearMonth(); +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/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js new file mode 100644 index 0000000000..79fdfa229c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.toplainyearmonth +description: Throw when the returned value is not a PlainYearMonth. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + yearMonthFromFields() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.PlainYearMonth, "Temporal.PlainYearMonth"], + [Temporal.PlainYearMonth.prototype, "Temporal.PlainYearMonth.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws(TypeError, () => plainDate.toPlainYearMonth(), `Expected error with ${description}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..71c8e2f012 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.toPlainYearMonth(); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..25e3db2553 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.toPlainYearMonth()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/duplicate-calendar-fields.js new file mode 100644 index 0000000000..31e21202a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + + assert.throws(RangeError, () => date.toPlainYearMonth()); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/length.js new file mode 100644 index 0000000000..c5166053c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: Temporal.PlainDate.prototype.toPlainYearMonth.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.PlainDate.prototype.toPlainYearMonth, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.js new file mode 100644 index 0000000000..e45d4b90b8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.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.plaindate.prototype.toplainyearmonth +description: toPlainYearMonth works within the supported range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const min = Temporal.PlainDate.from('-271821-04-19'); +TemporalHelpers.assertPlainYearMonth(min.toPlainYearMonth(), + -271821, 4, "M04", "min"); + +const max = Temporal.PlainDate.from('+275760-09-13'); +TemporalHelpers.assertPlainYearMonth(max.toPlainYearMonth(), + 275760, 9, "M09", "max"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/name.js new file mode 100644 index 0000000000..219f4134e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: Temporal.PlainDate.prototype.toPlainYearMonth.name is "toPlainYearMonth". +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.PlainDate.prototype.toPlainYearMonth, "name", { + value: "toPlainYearMonth", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/not-a-constructor.js new file mode 100644 index 0000000000..cd849a5ec4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: > + Temporal.PlainDate.prototype.toPlainYearMonth 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.PlainDate.prototype.toPlainYearMonth(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toPlainYearMonth), false, + "isConstructor(Temporal.PlainDate.prototype.toPlainYearMonth)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/prop-desc.js new file mode 100644 index 0000000000..b57bfe6a1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +description: The "toPlainYearMonth" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toPlainYearMonth, + "function", + "`typeof PlainDate.prototype.toPlainYearMonth` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toPlainYearMonth", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/proto-in-calendar-fields.js new file mode 100644 index 0000000000..91397b7c51 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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.plaindate.prototype.toplainyearmonth +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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.toPlainYearMonth()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/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/PlainDate/prototype/toString/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/basic.js new file mode 100644 index 0000000000..1b856747c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/basic.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.plaindate.protoype.tostring +description: basic tests +features: [Temporal] +---*/ + +const date1 = new Temporal.PlainDate(1976, 11, 18); +assert.sameValue(date1.toString(), "1976-11-18"); + +const date2 = new Temporal.PlainDate(1914, 2, 23); +assert.sameValue(date2.toString(), "1914-02-23"); + +const date3 = new Temporal.PlainDate(1996, 2, 29); +assert.sameValue(date3.toString(), "1996-02-29"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/branding.js new file mode 100644 index 0000000000..eb8f0cd16b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/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.plaindate.prototype.tostring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toString = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => toString.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..0ce71025f7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.toString(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/builtin.js new file mode 100644 index 0000000000..070c996b91 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.toString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendar-tostring.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendar-tostring.js new file mode 100644 index 0000000000..b09d756a6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 date = new Temporal.PlainDate(2000, 5, 2, customCalendar); +[ + ["always", "2000-05-02[u-ca=custom]", 1], + ["auto", "2000-05-02[u-ca=custom]", 1], + ["critical", "2000-05-02[!u-ca=custom]", 1], + ["never", "2000-05-02", 0], + [undefined, "2000-05-02[u-ca=custom]", 1], +].forEach(([calendarName, expectedResult, expectedCalls]) => { + calls = 0; + const result = date.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/PlainDate/prototype/toString/calendarname-always.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-always.js new file mode 100644 index 0000000000..686b38ffbf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-02[u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-02[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-02[u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-02[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-02[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDate(2000, 5, 2, ...args); + const result = date.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/PlainDate/prototype/toString/calendarname-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-auto.js new file mode 100644 index 0000000000..7b5e322e18 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-02", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-02[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-02", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-02[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-02[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDate(2000, 5, 2, ...args); + const result = date.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/PlainDate/prototype/toString/calendarname-critical.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-critical.js new file mode 100644 index 0000000000..ceb1876546 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-02[!u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-02[!u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-02[!u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-02[!u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-02[!u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDate(2000, 5, 2, ...args); + const result = date.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/PlainDate/prototype/toString/calendarname-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-invalid-string.js new file mode 100644 index 0000000000..6bdcddd835 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.protoype.tostring step 4: + 4. Let _showCalendar_ be ? ToShowCalendarOption(_options_). +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const invalidValues = ["ALWAYS", "sometimes", "other string", "auto\0"]; + +for (const calendarName of invalidValues) { + assert.throws( + RangeError, + () => date.toString({ calendarName }), + `${calendarName} is an invalid value for calendarName option` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-never.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-never.js new file mode 100644 index 0000000000..0c77b349f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-02", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-02", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-02", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-02", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-02", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDate(2000, 5, 2, ...args); + const result = date.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/PlainDate/prototype/toString/calendarname-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-undefined.js new file mode 100644 index 0000000000..ef4e32a99a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.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-02", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "2000-05-02[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "2000-05-02", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "2000-05-02[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "2000-05-02[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDate(2000, 5, 2, ...args); + const result = date.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/PlainDate/prototype/toString/calendarname-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/calendarname-wrong-type.js new file mode 100644 index 0000000000..2137bf50ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.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 date = new Temporal.PlainDate(2000, 5, 2, calendar); + +TemporalHelpers.checkStringOptionWrongType("calendarName", "auto", + (calendarName) => date.toString({ calendarName }), + (result, descr) => assert.sameValue(result, "2000-05-02[u-ca=custom]", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/length.js new file mode 100644 index 0000000000..43c3eefba3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: Temporal.PlainDate.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.PlainDate.prototype.toString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/name.js new file mode 100644 index 0000000000..f18c131ab2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: Temporal.PlainDate.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.PlainDate.prototype.toString, "name", { + value: "toString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/not-a-constructor.js new file mode 100644 index 0000000000..a3f47607d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: > + Temporal.PlainDate.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.PlainDate.prototype.toString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toString), false, + "isConstructor(Temporal.PlainDate.prototype.toString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-object.js new file mode 100644 index 0000000000..32da641983 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: Empty or a function object may be used as options +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.toString({}); +assert.sameValue( + result1, "2000-05-02", + "options may be an empty plain object" +); + +const result2 = instance.toString(() => {}); +assert.sameValue( + result2, "2000-05-02", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-undefined.js new file mode 100644 index 0000000000..5b44173c28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 date1 = new Temporal.PlainDate(2000, 5, 2); +const date2 = new Temporal.PlainDate(2000, 5, 2, calendar); + +[ + [date1, "2000-05-02"], + [date2, "2000-05-02[u-ca=custom]"], +].forEach(([date, expected]) => { + const explicit = date.toString(undefined); + assert.sameValue(explicit, expected, "default calendarName option is auto"); + + const implicit = date.toString(); + assert.sameValue(implicit, expected, "default calendarName option is auto"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/options-wrong-type.js new file mode 100644 index 0000000000..5b0589dc3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/order-of-operations.js new file mode 100644 index 0000000000..1872b8b5ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, 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/PlainDate/prototype/toString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/prop-desc.js new file mode 100644 index 0000000000..4575c55739 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/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.plaindate.prototype.tostring +description: The "toString" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toString, + "function", + "`typeof PlainDate.prototype.toString` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/toString/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toString/year-format.js new file mode 100644 index 0000000000..e6e29731c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDate(-100000, 12, 3); +assert.sameValue(instance.toString(), "-100000-12-03", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-10000, 4, 5); +assert.sameValue(instance.toString(), "-010000-04-05", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-9999, 6, 7); +assert.sameValue(instance.toString(), "-009999-06-07", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1000, 8, 9); +assert.sameValue(instance.toString(), "-001000-08-09", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-999, 10, 9); +assert.sameValue(instance.toString(), "-000999-10-09", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDate(-1, 8, 7); +assert.sameValue(instance.toString(), "-000001-08-07", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDate(0, 6, 5); +assert.sameValue(instance.toString(), "0000-06-05", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDate(1, 4, 3); +assert.sameValue(instance.toString(), "0001-04-03", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDate(999, 2, 10); +assert.sameValue(instance.toString(), "0999-02-10", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(1000, 1, 23); +assert.sameValue(instance.toString(), "1000-01-23", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(9999, 4, 5); +assert.sameValue(instance.toString(), "9999-04-05", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDate(10000, 6, 7); +assert.sameValue(instance.toString(), "+010000-06-07", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDate(100000, 8, 9); +assert.sameValue(instance.toString(), "+100000-08-09", "large positive year formatted as 6-digit"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/prop-desc.js new file mode 100644 index 0000000000..d5e25e8242 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype-@@tostringtag +description: The @@toStringTag property of Temporal.PlainDate +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainDate.prototype, Symbol.toStringTag, { + value: "Temporal.PlainDate", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toStringTag/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-number.js new file mode 100644 index 0000000000..6c45963cf3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: A number is invalid in place of an ISO string for Temporal.PlainTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const numbers = [ + 1, + -123456.987654321, + 1234567, + 123456.9876543219, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `A number (${arg}) is not a valid ISO string for PlainTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..b6135a89ea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-calendar-annotation.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.tozoneddatetime +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["12:34:56.987654321[u-ca=iso8601]", "without time zone"], + ["12:34:56.987654321[UTC][u-ca=iso8601]", "with time zone"], + ["12:34:56.987654321[!u-ca=iso8601]", "with ! and no time zone"], + ["12:34:56.987654321[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["T12:34:56.987654321[u-ca=iso8601]", "with T and no time zone"], + ["T12:34:56.987654321[UTC][u-ca=iso8601]", "with T and time zone"], + ["T12:34:56.987654321[!u-ca=iso8601]", "with T, !, and no time zone"], + ["T12:34:56.987654321[UTC][!u-ca=iso8601]", "with T, !, and time zone"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601]", "with date and no time zone"], + ["1970-01-01T12:34:56.987654321[UTC][u-ca=iso8601]", "with date and time zone"], + ["1970-01-01T12:34:56.987654321[!u-ca=iso8601]", "with !, date, and no time zone"], + ["1970-01-01T12:34:56.987654321[UTC][!u-ca=iso8601]", "with !, date, and time zone"], + ["12:34:56.987654321[u-ca=hebrew]", "calendar annotation ignored"], + ["12:34:56.987654321[u-ca=unknown]", "calendar annotation ignored even if unknown calendar"], + ["12:34:56.987654321[!u-ca=unknown]", "calendar annotation ignored even if unknown calendar with !"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + assert.sameValue( + result.epochNanoseconds, + 957_270_896_987_654_321n, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..7f3c36037b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-critical-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.plaindate.prototype.tozoneddatetime +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[!foo=bar]", + "T00:00[!foo=bar]", + "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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..6c9d395886 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-date-with-utc-offset.js @@ -0,0 +1,52 @@ +// |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.plaindate.prototype.tozoneddatetime +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const validStrings = [ + "12:34:56.987654321+00:00", + "12:34:56.987654321+00:00[UTC]", + "12:34:56.987654321+00:00[!UTC]", + "12:34:56.987654321-02:30[America/St_Johns]", + "1976-11-18T12:34:56.987654321+00:00", + "1976-11-18T12:34:56.987654321+00:00[UTC]", + "1976-11-18T12:34:56.987654321+00:00[!UTC]", + "1976-11-18T12:34:56.987654321-02:30[America/St_Johns]", +]; + +for (const arg of validStrings) { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + assert.sameValue( + result.epochNanoseconds, + 957_270_896_987_654_321n, + `"${arg}" is a valid UTC offset with time for PlainTime` + ); +} + +const invalidStrings = [ + "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.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `"${arg}" UTC offset without time is not valid for PlainTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..527260a260 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[u-ca=iso8601][!u-ca=iso8601]", + "00:00[!u-ca=iso8601][u-ca=iso8601]", + "00:00[UTC][u-ca=iso8601][!u-ca=iso8601]", + "00:00[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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..c72d9cc208 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-multiple-time-zone.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.plaindate.prototype.tozoneddatetime +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "00:00[UTC][UTC]", + "T00:00[UTC][UTC]", + "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.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-no-implicit-midnight.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-no-implicit-midnight.js new file mode 100644 index 0000000000..8845c8cd45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-no-implicit-midnight.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if a date-only string is passed in a PlainTime context +features: [Temporal, arrow-function] +---*/ + +const arg = "2019-10-01"; +const instance = new Temporal.PlainDate(2000, 5, 2); +assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + "Date-only string throws, does not implicitly convert to midnight" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-designator-required-for-disambiguation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-designator-required-for-disambiguation.js new file mode 100644 index 0000000000..99693c739d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-designator-required-for-disambiguation.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.plaindate.prototype.tozoneddatetime +description: ISO 8601 time designator "T" required in cases of ambiguity +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +TemporalHelpers.ISO.plainTimeStringsAmbiguous().forEach((string) => { + let arg = string; + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `'${arg}' is ambiguous and requires T prefix` + ); + // The same string with a T prefix should not throw: + arg = `T${string}`; + instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + arg = ` ${string}`; + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `space is not accepted as a substitute for T prefix: '${arg}'` + ); +}); + +// None of these should throw without a T prefix, because they are unambiguously time strings: +TemporalHelpers.ISO.plainTimeStringsUnambiguous().forEach( + (arg) => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-separators.js new file mode 100644 index 0000000000..2855e5ffd9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-separators.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.plaindate.prototype.tozoneddatetime +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18T12:34:56.987654321", "uppercase T"], + ["1976-11-18t12:34:56.987654321", "lowercase T"], + ["1976-11-18 12:34:56.987654321", "space between date and time"], + ["T12:34:56.987654321", "time-only uppercase T"], + ["t12:34:56.987654321", "time-only lowercase T"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + assert.sameValue( + result.epochNanoseconds, + 957_270_896_987_654_321n, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..03aa7e6b03 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-zone-annotation.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.plaindate.prototype.tozoneddatetime +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["12:34:56.987654321[Asia/Kolkata]", "named, with no offset"], + ["12:34:56.987654321[!Europe/Vienna]", "named, with ! and no offset"], + ["12:34:56.987654321[+00:00]", "numeric, with no offset"], + ["12:34:56.987654321[!-02:30]", "numeric, with ! and no offset"], + ["T12:34:56.987654321[UTC]", "named, with T and no offset"], + ["T12:34:56.987654321[!Africa/Abidjan]", "named, with T, !, and no offset"], + ["T12:34:56.987654321[+01:00]", "numeric, with T and no offset"], + ["T12:34:56.987654321[!-08:00]", "numeric, with T, !, and no offset"], + ["12:34:56.987654321+00:00[America/Sao_Paulo]", "named, with offset"], + ["12:34:56.987654321+00:00[!Asia/Tokyo]", "named, with ! and offset"], + ["12:34:56.987654321+00:00[-02:30]", "numeric, with offset"], + ["12:34:56.987654321+00:00[!+00:00]", "numeric, with ! and offset"], + ["T12:34:56.987654321+00:00[America/New_York]", "named, with T and offset"], + ["T12:34:56.987654321+00:00[!UTC]", "named, with T, !, and offset"], + ["T12:34:56.987654321+00:00[-08:00]", "numeric, with T and offset"], + ["T12:34:56.987654321+00:00[!+01:00]", "numeric, with T, !, and offset"], + ["1970-01-01T12:34:56.987654321[Africa/Lagos]", "named, with date and no offset"], + ["1970-01-01T12:34:56.987654321[!America/Vancouver]", "named, with date, !, and no offset"], + ["1970-01-01T12:34:56.987654321[+00:00]", "numeric, with date and no offset"], + ["1970-01-01T12:34:56.987654321[!-02:30]", "numeric, with date, !, and no offset"], + ["1970-01-01T12:34:56.987654321+00:00[Europe/London]", "named, with date and offset"], + ["1970-01-01T12:34:56.987654321+00:00[!Asia/Seoul]", "named, with date, offset, and !"], + ["1970-01-01T12:34:56.987654321+00:00[+01:00]", "numeric, with date and offset"], + ["1970-01-01T12:34:56.987654321+00:00[!-08:00]", "numeric, with date, offset, and !"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + assert.sameValue( + result.epochNanoseconds, + 957_270_896_987_654_321n, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..83c2cf209f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-unknown-annotation.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.tozoneddatetime +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["12:34:56.987654321[foo=bar]", "alone"], + ["12:34:56.987654321[UTC][foo=bar]", "with time zone"], + ["12:34:56.987654321[u-ca=iso8601][foo=bar]", "with calendar"], + ["12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["T12:34:56.987654321[foo=bar]", "with T"], + ["T12:34:56.987654321[UTC][foo=bar]", "with T and time zone"], + ["T12:34:56.987654321[u-ca=iso8601][foo=bar]", "with T and calendar"], + ["T12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with T, time zone, and calendar"], + ["1970-01-01T12:34:56.987654321[foo=bar]", "with date"], + ["1970-01-01T12:34:56.987654321[UTC][foo=bar]", "with date and time zone"], + ["1970-01-01T12:34:56.987654321[u-ca=iso8601][foo=bar]", "with date and calendar"], + ["1970-01-01T12:34:56.987654321[UTC][foo=bar][u-ca=iso8601]", "with date, time zone, and calendar"], + ["1970-01-01T12:34:56.987654321[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +tests.forEach(([arg, description]) => { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + + assert.sameValue( + result.epochNanoseconds, + 957_270_896_987_654_321n, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-time-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-time-designator.js new file mode 100644 index 0000000000..d5fb0b8304 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-time-designator.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.plaindate.prototype.tozoneddatetime +description: ISO 8601 time designator "T" allowed at the start of PlainTime strings +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDate(2000, 1, 1); +const validStrings = [ + "T00:30", + "t00:30", + "T0030", + "t0030", + "T00:30:00", + "t00:30:00", + "T003000", + "t003000", + "T00:30:00.000000000", + "t00:30:00.000000000", + "T003000.000000000", + "t003000.000000000", +]; +validStrings.forEach((arg) => { + const result = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); + assert.sameValue(result.epochNanoseconds, 946686600_000_000_000n, `T prefix is accepted: ${arg}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..fe1278b2c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-with-utc-designator.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if a string with UTC designator is used as a PlainTime +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", + "09:00:00Z[UTC]", + "09:00:00Z", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + "String with UTC designator should not be valid as a PlainTime" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-wrong-type.js new file mode 100644 index 0000000000..e2f64f517b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-wrong-type.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.tozoneddatetime +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainTime +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "plain object"], + [Temporal.PlainTime, "Temporal.PlainTime, object"], + [Temporal.PlainTime.prototype, "Temporal.PlainTime.prototype, object"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), `${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/PlainDate/prototype/toZonedDateTime/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..f8cb95c755 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-zoneddatetime-negative-epochnanoseconds.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.plaindate.prototype.tozoneddatetime +description: A pre-epoch value is handled correctly by the modulo operation in GetISOPartsFromEpoch +info: | + sec-temporal-getisopartsfromepoch step 1: + 1. Let _remainderNs_ be the mathematical value whose sign is the sign of _epochNanoseconds_ and whose magnitude is abs(_epochNanoseconds_) modulo 10<sup>6</sup>. + sec-temporal-builtintimezonegetplaindatetimefor step 2: + 2. Let _result_ be ! GetISOPartsFromEpoch(_instant_.[[Nanoseconds]]). +features: [Temporal] +---*/ + +const datetime = new Temporal.ZonedDateTime(-13849764_999_999_999n, "UTC"); + +// This code path shows up anywhere we convert an exact time, before the Unix +// epoch, with nonzero microseconds or nanoseconds, into a wall time. + +const instance = new Temporal.PlainDate(2000, 5, 2); +const result = instance.toZonedDateTime({ plainTime: datetime, timeZone: "UTC" }); +assert.sameValue(result.epochNanoseconds, 957286235_000_000_001n); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/basic.js new file mode 100644 index 0000000000..1811886891 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/basic.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.plaindate.prototype.tozoneddatetime +description: Basic tests for toZonedDateTime(). +features: [Temporal] +---*/ + +const plainDate = Temporal.PlainDate.from("2020-01-01"); +const timeZone = Temporal.TimeZone.from("UTC"); +const plainTime = Temporal.PlainTime.from("12:00"); + +let result = plainDate.toZonedDateTime({ timeZone, plainTime }); +assert.sameValue(result.toString(), "2020-01-01T12:00:00+00:00[UTC]", "objects passed"); + +result = plainDate.toZonedDateTime(timeZone); +assert.sameValue(result.toString(), "2020-01-01T00:00:00+00:00[UTC]", "time zone object argument"); + +result = plainDate.toZonedDateTime("UTC"); +assert.sameValue(result.toString(), "2020-01-01T00:00:00+00:00[UTC]", "time zone string argument"); + +result = plainDate.toZonedDateTime({ timeZone }); +assert.sameValue(result.toString(), "2020-01-01T00:00:00+00:00[UTC]", "time zone object property"); + +result = plainDate.toZonedDateTime({ timeZone: "UTC", plainTime }); +assert.sameValue(result.toString(), "2020-01-01T12:00:00+00:00[UTC]", "time zone string property"); + +result = plainDate.toZonedDateTime({ timeZone, plainTime: "12:00" }); +assert.sameValue(result.toString(), "2020-01-01T12:00:00+00:00[UTC]", "time string property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/branding.js new file mode 100644 index 0000000000..9eddebf6d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toZonedDateTime = Temporal.PlainDate.prototype.toZonedDateTime; + +assert.sameValue(typeof toZonedDateTime, "function"); + +const args = [new Temporal.TimeZone("UTC")]; + +assert.throws(TypeError, () => toZonedDateTime.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => toZonedDateTime.apply(null, args), "null"); +assert.throws(TypeError, () => toZonedDateTime.apply(true, args), "true"); +assert.throws(TypeError, () => toZonedDateTime.apply("", args), "empty string"); +assert.throws(TypeError, () => toZonedDateTime.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => toZonedDateTime.apply(1, args), "1"); +assert.throws(TypeError, () => toZonedDateTime.apply({}, args), "plain object"); +assert.throws(TypeError, () => toZonedDateTime.apply(Temporal.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => toZonedDateTime.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/builtin.js new file mode 100644 index 0000000000..c31498e3c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: > + Tests that Temporal.PlainDate.prototype.toZonedDateTime + 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.PlainDate.prototype.toZonedDateTime), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.toZonedDateTime), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.toZonedDateTime), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.toZonedDateTime.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/calendar.js new file mode 100644 index 0000000000..485ee36087 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/calendar.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.plaindate.prototype.tozoneddatetime +description: Calendar of the receiver is used +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +const timeCalendar = { toString() { return "iso8601"; } }; +const plainDate = new Temporal.PlainDate(2000, 5, 2, calendar); +const result = plainDate.toZonedDateTime({ + timeZone: "UTC", + plainTime: { hour: 12, minute: 30, calendar: timeCalendar }, +}); +assert.sameValue(result.epochNanoseconds, 957270600_000_000_000n); +assert.sameValue(result.timeZoneId, "UTC"); +assert.sameValue(result.getCalendar(), calendar); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/getpossibleinstantsfor-called-with-iso8601-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/getpossibleinstantsfor-called-with-iso8601-calendar.js new file mode 100644 index 0000000000..9dcceb14a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/getpossibleinstantsfor-called-with-iso8601-calendar.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.plaindate.prototype.tozoneddatetime +description: > + Time zone's getPossibleInstantsFor is called with a PlainDateTime with the + built-in ISO 8601 calendar +features: [Temporal] +info: | + DisambiguatePossibleInstants: + 2. Let _n_ be _possibleInstants_'s length. + ... + 5. Assert: _n_ = 0. + ... + 19. If _disambiguation_ is *"earlier"*, then + ... + c. Let _earlierDateTime_ be ! CreateTemporalDateTime(..., *"iso8601"*). + d. Set _possibleInstants_ to ? GetPossibleInstantsFor(_timeZone_, _earlierDateTime_). + ... + 20. Assert: _disambiguation_ is *"compatible"* or *"later"*. + ... + 23. Let _laterDateTime_ be ! CreateTemporalDateTime(..., *"iso8601"*). + 24. Set _possibleInstants_ to ? GetPossibleInstantsFor(_timeZone_, _laterDateTime_). +---*/ + +class SkippedDateTime extends Temporal.TimeZone { + constructor() { + super("UTC"); + this.calls = 0; + } + + getPossibleInstantsFor(dateTime) { + // Calls occur in pairs. For the first one return no possible instants so + // that DisambiguatePossibleInstants will call it again + if (this.calls++ % 2 == 0) { + return []; + } + + assert.sameValue( + dateTime.getISOFields().calendar, + "iso8601", + "getPossibleInstantsFor called with dateTime with built-in ISO 8601 calendar" + ); + return super.getPossibleInstantsFor(dateTime); + } +} + +const nonBuiltinISOCalendar = new Temporal.Calendar("iso8601"); +const timeZone = new SkippedDateTime(); + +const instance = new Temporal.PlainDate(2000, 5, 2, nonBuiltinISOCalendar); +instance.toZonedDateTime(timeZone); + +assert.sameValue(timeZone.calls, 2, "getPossibleInstantsFor should have been called 2 times"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/leap-second.js new file mode 100644 index 0000000000..2560495911 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: Leap second is a valid ISO string for PlainTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); +assert.sameValue( + result1.epochNanoseconds, + 957311999_000_000_000n, + "leap second is a valid ISO string for PlainTime" +); + +arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; +const result2 = instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }); +assert.sameValue( + result2.epochNanoseconds, + 957311999_000_000_000n, + "second: 60 is ignored in property bag for PlainTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/length.js new file mode 100644 index 0000000000..405ef56df9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: Temporal.PlainDate.prototype.toZonedDateTime.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.PlainDate.prototype.toZonedDateTime, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/name.js new file mode 100644 index 0000000000..15818816d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: Temporal.PlainDate.prototype.toZonedDateTime.name is "toZonedDateTime". +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.PlainDate.prototype.toZonedDateTime, "name", { + value: "toZonedDateTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/not-a-constructor.js new file mode 100644 index 0000000000..80ad27d974 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: > + Temporal.PlainDate.prototype.toZonedDateTime 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.PlainDate.prototype.toZonedDateTime(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.toZonedDateTime), false, + "isConstructor(Temporal.PlainDate.prototype.toZonedDateTime)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/order-of-operations.js new file mode 100644 index 0000000000..b84a4c5fa4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/order-of-operations.js @@ -0,0 +1,98 @@ +// |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.plaindate.prototype.tozoneddatetime +description: User code calls happen in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + "get item.timeZone", + "has item.timeZone.getOffsetNanosecondsFor", + "has item.timeZone.getPossibleInstantsFor", + "has item.timeZone.id", + "get item.plainTime", + // ToTemporalTime + "get item.plainTime.hour", + "get item.plainTime.hour.valueOf", + "call item.plainTime.hour.valueOf", + "get item.plainTime.microsecond", + "get item.plainTime.microsecond.valueOf", + "call item.plainTime.microsecond.valueOf", + "get item.plainTime.millisecond", + "get item.plainTime.millisecond.valueOf", + "call item.plainTime.millisecond.valueOf", + "get item.plainTime.minute", + "get item.plainTime.minute.valueOf", + "call item.plainTime.minute.valueOf", + "get item.plainTime.nanosecond", + "get item.plainTime.nanosecond.valueOf", + "call item.plainTime.nanosecond.valueOf", + "get item.plainTime.second", + "get item.plainTime.second.valueOf", + "call item.plainTime.second.valueOf", + // lookup in PlainDate.p.toZonedDateTime + "get item.timeZone.getOffsetNanosecondsFor", + "get item.timeZone.getPossibleInstantsFor", + // GetInstantFor + "call item.timeZone.getPossibleInstantsFor", +]; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 1, 1, calendar); +const springForwardInstance = new Temporal.PlainDate(2000, 4, 2, calendar); +const fallBackInstance = new Temporal.PlainDate(2000, 10, 29, calendar); +actual.splice(0); // clear calendar calls that happened in constructors + +const plainTime = TemporalHelpers.propertyBagObserver(actual, { + hour: 2, + minute: 30, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, +}, "item.plainTime"); +const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone(); +const timeZone = TemporalHelpers.timeZoneObserver(actual, "item.timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); +const item = TemporalHelpers.propertyBagObserver(actual, { + plainTime, + timeZone, +}, "item"); + +instance.toZonedDateTime(item); +assert.compareArray(actual, expected, "order of operations at normal wall-clock time"); +actual.splice(0); // clear + +const plainTime130 = TemporalHelpers.propertyBagObserver(actual, { + hour: 1, + minute: 30, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, +}, "item.plainTime"); +const item130 = TemporalHelpers.propertyBagObserver(actual, { + plainTime: plainTime130, + timeZone, +}, "item"); + +fallBackInstance.toZonedDateTime(item130); +assert.compareArray(actual, expected, "order of operations at repeated wall-clock time"); +actual.splice(0); // clear + +springForwardInstance.toZonedDateTime(item); +assert.compareArray(actual, expected.concat([ + "call item.timeZone.getOffsetNanosecondsFor", + "call item.timeZone.getOffsetNanosecondsFor", + "call item.timeZone.getPossibleInstantsFor", +]), "order of operations at skipped wall-clock time"); +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..e631b28963 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-balance-negative-time-units.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.plaindate.prototype.tozoneddatetime +description: Negative time fields are balanced upwards in a ZonedDateTime given as plainTime +info: | + sec-temporal-balancetime steps 3–14: + 3. Set _microsecond_ to _microsecond_ + floor(_nanosecond_ / 1000). + 4. Set _nanosecond_ to _nanosecond_ modulo 1000. + 5. Set _millisecond_ to _millisecond_ + floor(_microsecond_ / 1000). + 6. Set _microsecond_ to _microsecond_ modulo 1000. + 7. Set _second_ to _second_ + floor(_millisecond_ / 1000). + 8. Set _millisecond_ to _millisecond_ modulo 1000. + 9. Set _minute_ to _minute_ + floor(_second_ / 60). + 10. Set _second_ to _second_ modulo 60. + 11. Set _hour_ to _hour_ + floor(_minute_ / 60). + 12. Set _minute_ to _minute_ modulo 60. + 13. Let _days_ be floor(_hour_ / 24). + 14. Set _hour_ to _hour_ modulo 24. + sec-temporal-balanceisodatetime step 1: + 1. Let _balancedTime_ be ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_). + sec-temporal-builtintimezonegetplaindatetimefor step 3: + 3. Set _result_ to ? BalanceISODateTime(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]] + _offsetNanoseconds_). + sec-temporal-totemporaltime step 3.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + ... + ii. 1. Set _plainDateTime_ to ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). + sec-temporal.plaindate.prototype.tozoneddatetime step 6.a: + a. Set _temporalTime_ to ? ToTemporalTime(_temporalTime_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// This code path is encountered if the time zone offset is negative and its +// absolute value in nanoseconds is greater than the nanosecond field of the +// exact time's epoch parts +const tz = TemporalHelpers.specificOffsetTimeZone(-2); +const datetime = new Temporal.ZonedDateTime(3661_001_001_001n, tz); + +const otherTimeZone = new Temporal.TimeZone("UTC"); // should not be used to convert datetime to PlainTime +const date = new Temporal.PlainDate(2000, 5, 2); +const zdt = date.toZonedDateTime({ timeZone: otherTimeZone, plainTime: datetime }); + +assert.sameValue(zdt.microsecond, 0); +assert.sameValue(zdt.nanosecond, 999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..576fc4b23a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.toZonedDateTime({ plainTime: datetime, timeZone: "UTC" })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..7adf2dd547 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.tozoneddatetime +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.toZonedDateTime({ plainTime: datetime, timeZone: "UTC" }), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..d29f3afa1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.toZonedDateTime({ plainTime: datetime, timeZone: "UTC" })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..f2ad7aa761 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.prototype.tozoneddatetime +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => date.toZonedDateTime({ plainTime: datetime, timeZone: "UTC" })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-propertybag-no-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-propertybag-no-time-units.js new file mode 100644 index 0000000000..f29691c8c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/plaintime-propertybag-no-time-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.plaindate.prototype.tozoneddatetime +description: Missing time units in property bag default to 0 +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 1, 1); + +const props = {}; +assert.throws(TypeError, () => instance.toZonedDateTime({ plainTime: props, timeZone: "UTC" }), "TypeError if no properties are present"); + +props.minute = 30; +const result = instance.toZonedDateTime({ plainTime: props, timeZone: "UTC" }); +assert.sameValue(result.epochNanoseconds, 946686600_000_000_000n, "missing time units default to 0"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/prop-desc.js new file mode 100644 index 0000000000..04db137fc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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.plaindate.prototype.tozoneddatetime +description: The "toZonedDateTime" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.toZonedDateTime, + "function", + "`typeof PlainDate.prototype.toZonedDateTime` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "toZonedDateTime", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/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/PlainDate/prototype/toZonedDateTime/timezone-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-case-insensitive.js new file mode 100644 index 0000000000..9e66040e43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-case-insensitive.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.plaindate.prototype.tozoneddatetime +description: Time zone names are case insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const timeZone = 'uTc'; +const result = instance.toZonedDateTime(timeZone); +assert.sameValue(result.timeZoneId, 'UTC', `Time zone created from string "${timeZone}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..1b664b2991 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const plainTime = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(RangeError, () => date.toZonedDateTime({ plainTime, timeZone })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..d4096890d3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.tozoneddatetime +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const plainTime = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.toZonedDateTime({ plainTime, timeZone }), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..8d96870354 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.tozoneddatetime +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const plainTime = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(RangeError, () => date.toZonedDateTime({ plainTime, timeZone })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..d59f7149ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-wrong-type.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.plaindate.prototype.tozoneddatetime +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const plainTime = new Temporal.PlainTime(12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(TypeError, () => date.toZonedDateTime({ plainTime, timeZone })); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js new file mode 100644 index 0000000000..05331a4606 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.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.plaindate.prototype.tozoneddatetime +description: An iterable returned from timeZone.getPossibleInstantsFor is consumed after each call +info: | + sec-temporal.plaindate.prototype.tozoneddatetime step 7: + 7. Let _instant_ be ? BuiltinTimeZoneGetInstantFor(_timeZone_, _temporalDateTime_, *"compatible"*). + sec-temporal-builtintimezonegetinstantfor step 1: + 1. Let _possibleInstants_ be ? GetPossibleInstantsFor(_timeZone_, _dateTime_). + sec-temporal-builtintimezonegetinstantfor step 14: + 14. Assert: _disambiguation_ is *"compatible"* or *"later"*. + sec-temporal-builtintimezonegetinstantfor step 16: + 16. Set _possibleInstants_ to ? GetPossibleInstantsFor(_timeZone_, _later_). + sec-temporal-getpossibleinstantsfor step 2: + 2. Let _list_ be ? IterableToList(_possibleInstants_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected1 = [ + "2000-05-02T00:00:00", +]; + +TemporalHelpers.checkTimeZonePossibleInstantsIterable((timeZone) => { + const date = new Temporal.PlainDate(2000, 5, 2); + date.toZonedDateTime(timeZone); +}, expected1); + +// Same, but test the other path where the time doesn't exist and +// GetPossibleInstantsFor is called again on a later time + +const expected2 = [ + "2030-01-01T00:30:00", + "2030-01-01T01:30:00", +]; + +TemporalHelpers.checkTimeZonePossibleInstantsIterable((timeZone) => { + const date = new Temporal.PlainDate(2030, 1, 1); + date.toZonedDateTime({ plainTime: new Temporal.PlainTime(0, 30), timeZone }); +}, expected2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor.js new file mode 100644 index 0000000000..1a1d2f8494 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor.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.plaindate.prototype.tozoneddatetime +description: Calendar of the receiver is used +features: [Temporal] +---*/ + +const calendar = new Temporal.Calendar("iso8601"); +class CustomTimeZone extends Temporal.TimeZone { + constructor() { + super("UTC"); + } + getPossibleInstantsFor(plainDateTime) { + assert.sameValue(plainDateTime.getCalendar(), calendar); + return [new Temporal.Instant(987654321_000_000_000n)]; + } +} +const timeZone = new CustomTimeZone(); +const plainDate = new Temporal.PlainDate(2000, 5, 2, calendar); +const result = plainDate.toZonedDateTime({ + timeZone, + plainTime: { hour: 12, minute: 30 }, +}); +assert.sameValue(result.epochNanoseconds, 987654321_000_000_000n); +assert.sameValue(result.getTimeZone(), timeZone); +assert.sameValue(result.getCalendar(), calendar); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-datetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-datetime.js new file mode 100644 index 0000000000..24c2c66267 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-datetime.js @@ -0,0 +1,65 @@ +// |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.plaindate.prototype.tozoneddatetime +description: Conversion of ISO date-time strings to Temporal.TimeZone instances +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +let timeZone = "2021-08-19T17:30"; +assert.throws(RangeError, () => instance.toZonedDateTime(timeZone), "bare date-time string is not a time zone"); + +[ + "2021-08-19T17:30-07:00:01", + "2021-08-19T17:30-07:00:00", + "2021-08-19T17:30-07:00:00.1", + "2021-08-19T17:30-07:00:00.0", + "2021-08-19T17:30-07:00:00.01", + "2021-08-19T17:30-07:00:00.00", + "2021-08-19T17:30-07:00:00.001", + "2021-08-19T17:30-07:00:00.000", + "2021-08-19T17:30-07:00:00.0001", + "2021-08-19T17:30-07:00:00.0000", + "2021-08-19T17:30-07:00:00.00001", + "2021-08-19T17:30-07:00:00.00000", + "2021-08-19T17:30-07:00:00.000001", + "2021-08-19T17:30-07:00:00.000000", + "2021-08-19T17:30-07:00:00.0000001", + "2021-08-19T17:30-07:00:00.0000000", + "2021-08-19T17:30-07:00:00.00000001", + "2021-08-19T17:30-07:00:00.00000000", + "2021-08-19T17:30-07:00:00.000000001", + "2021-08-19T17:30-07:00:00.000000000", +].forEach((timeZone) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime(timeZone), + `ISO string ${timeZone} with a sub-minute offset is not a valid time zone` + ); +}); + +timeZone = "2021-08-19T17:30Z"; +const result1 = instance.toZonedDateTime(timeZone); +assert.sameValue(result1.timeZoneId, "UTC", "date-time + Z is UTC time zone"); + +timeZone = "2021-08-19T17:30-07:00"; +const result2 = instance.toZonedDateTime(timeZone); +assert.sameValue(result2.timeZoneId, "-07:00", "date-time + offset is the offset time zone"); + +timeZone = "2021-08-19T17:30[UTC]"; +const result3 = instance.toZonedDateTime(timeZone); +assert.sameValue(result3.timeZoneId, "UTC", "date-time + IANA annotation is the IANA time zone"); + +timeZone = "2021-08-19T17:30Z[UTC]"; +const result4 = instance.toZonedDateTime(timeZone); +assert.sameValue(result4.timeZoneId, "UTC", "date-time + Z + IANA annotation is the IANA time zone"); + +timeZone = "2021-08-19T17:30-07:00[UTC]"; +const result5 = instance.toZonedDateTime(timeZone); +assert.sameValue(result5.timeZoneId, "UTC", "date-time + offset + IANA annotation is the IANA time zone"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-leap-second.js new file mode 100644 index 0000000000..ee9b23f844 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-leap-second.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.plaindate.prototype.tozoneddatetime +description: Leap second is a valid ISO string for TimeZone +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +let timeZone = "2016-12-31T23:59:60+00:00[UTC]"; + +const result = instance.toZonedDateTime(timeZone); +assert.sameValue(result.timeZoneId, "UTC", "leap second is a valid ISO string for TimeZone"); + +timeZone = "2021-08-19T17:30:45.123456789+23:59[+23:59:60]"; +assert.throws(RangeError, () => instance.toZonedDateTime(timeZone), "leap second in time zone name not valid"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-multiple-offsets.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-multiple-offsets.js new file mode 100644 index 0000000000..144bf2d184 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-multiple-offsets.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.plaindate.prototype.tozoneddatetime +description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]"; + +const result = instance.toZonedDateTime(timeZone); +assert.sameValue(result.timeZoneId, "+01:46", "Time zone string determined from bracket name"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-year-zero.js new file mode 100644 index 0000000000..f17dae299b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-year-zero.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.plaindate.prototype.tozoneddatetime +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31T17:45Z", + "-000000-10-31T17:45+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((timeZone) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime(timeZone), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string.js new file mode 100644 index 0000000000..80efaabacc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.tozoneddatetime +description: Time zone IDs are valid input for a time zone +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const getPossibleInstantsForOriginal = Object.getOwnPropertyDescriptor(Temporal.TimeZone.prototype, "getPossibleInstantsFor"); +Object.defineProperty(Temporal.TimeZone.prototype, "getPossibleInstantsFor", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("getPossibleInstantsFor should not be looked up"); + }, +}); +const getOffsetNanosecondsForOriginal = Object.getOwnPropertyDescriptor(Temporal.TimeZone.prototype, "getOffsetNanosecondsFor"); +Object.defineProperty(Temporal.TimeZone.prototype, "getOffsetNanosecondsFor", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("getOffsetNanosecondsFor should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2); + +["UTC", "+01:30"].forEach((timeZone) => { + const result = instance.toZonedDateTime(timeZone); + assert.sameValue(result.getISOFields().timeZone, timeZone, `time zone slot should store string "${timeZone}"`); +}); + +Object.defineProperty(Temporal.TimeZone.prototype, "getPossibleInstantsFor", getPossibleInstantsForOriginal); +Object.defineProperty(Temporal.TimeZone.prototype, "getOffsetNanosecondsFor", getOffsetNanosecondsForOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-wrong-type.js new file mode 100644 index 0000000000..88b2ae55d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-wrong-type.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.tozoneddatetime +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or object for TimeZone +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const primitiveTests = [ + [null, "null"], + [true, "boolean"], + ["", "empty string"], + [1, "number that doesn't convert to a valid ISO string"], + [19761118, "number that would convert to a valid ISO string in other contexts"], + [1n, "bigint"], +]; + +for (const [timeZone, description] of primitiveTests) { + assert.throws( + typeof timeZone === 'string' ? RangeError : TypeError, + () => instance.toZonedDateTime(timeZone), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [{}, "object not implementing time zone protocol"], + [new Temporal.Calendar("iso8601"), "calendar instance"], +]; + +for (const [timeZone, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.toZonedDateTime(timeZone), `${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/PlainDate/prototype/toZonedDateTime/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/year-zero.js new file mode 100644 index 0000000000..99b5545515 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/toZonedDateTime/year-zero.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.plaindate.prototype.tozoneddatetime +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-12-07T03:24:30", + "-000000-12-07T03:24:30+01:00", + "-000000-12-07T03:24:30+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.toZonedDateTime({ plainTime: arg, timeZone: "UTC" }), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..65a50eeeb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" }; +instance.until(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..81df965c93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-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.plaindate.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.PlainDate(2000, 5, 2); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.until(arg); +assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..11d0874d9f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..ef00260ae3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-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.plaindate.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'], ['day'], ['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.PlainDate(2000, 5, 2); + + assert.throws(RangeError, () => instance.until(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-leap-second.js new file mode 100644 index 0000000000..e62b69de21 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-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.plaindate.prototype.until +description: Leap second is a valid ISO string for PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2016, 12, 31); + +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 PlainDate" +); + +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 PlainDate" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-number.js new file mode 100644 index 0000000000..c181972581 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.until(arg), + 'Numbers cannot be used in place of an ISO string for PlainDate' + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-plaindatetime.js new file mode 100644 index 0000000000..8dfa1b88ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-plaindatetime.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.plaindate.until +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindate.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.b: + b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then + i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => { + const date = new Temporal.PlainDate(2000, 5, 2); + const result = date.until(datetime); + assert.sameValue(result.total({ unit: "nanoseconds" }), 0, "time part dropped"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..c3a029272a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/until/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..a05da04f05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1976, 11, 18); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/until/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..c46e6ff2ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/until/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..2dddc518d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, 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/PlainDate/prototype/until/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..65304590aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/until/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..abe100487e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/until/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..01c0f901aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-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.plaindate.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.PlainDate(2000, 5, 2); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..a19cb0caff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-calendar-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.plaindate.prototype.until +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[u-ca=iso8601]", "without time or time zone"], + ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"], + ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"], + ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/until/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..ac10df4a67 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-critical-unknown-annotation.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.plaindate.prototype.until +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[!foo=bar]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/until/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..06692bd6b3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-date-with-utc-offset.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.plaindate.prototype.until +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const validStrings = [ + "2000-05-02T00+00:00", + "2000-05-02T00+00:00[UTC]", + "2000-05-02T00+00:00[!UTC]", + "2000-05-02T00-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 PlainDate` + ); +} + +const invalidStrings = [ + "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 PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js new file mode 100644 index 0000000000..47c10e5c58 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-invalid.js @@ -0,0 +1,64 @@ +// |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.plaindate.prototype.until +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.until(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..db7f9127f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/until/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..1ec82cadc5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-multiple-time-zone.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.plaindate.prototype.until +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01[UTC][UTC]", + "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.PlainDate(2000, 5, 2); +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/PlainDate/prototype/until/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-time-separators.js new file mode 100644 index 0000000000..e9c944cc64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02T15:23", "uppercase T"], + ["2000-05-02t15:23", "lowercase T"], + ["2000-05-02 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/until/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..f8cdb4306e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-time-zone-annotation.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[Asia/Kolkata]", "named, with no time"], + ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"], + ["2000-05-02[+00:00]", "numeric, with no time"], + ["2000-05-02[!-02:30]", "numeric, with ! and no time"], + ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"], + ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"], + ["2000-05-02T15:23[-02:30]", "numeric, with no offset"], + ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"], + ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"], + ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"], + ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"], + ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/until/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..c8b5af5c6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-unknown-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.plaindate.prototype.until +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["2000-05-02[foo=bar]", "without time"], + ["2000-05-02T15:23[foo=bar]", "alone"], + ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"], + ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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/PlainDate/prototype/until/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..95f193aed7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: RangeError thrown if a string with UTC designator is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + "String with UTC designator should not be valid as a PlainDate" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-wrong-type.js new file mode 100644 index 0000000000..d6886c8c7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDate +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +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.PlainDate, "Temporal.PlainDate, object"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.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/PlainDate/prototype/until/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-convert.js new file mode 100644 index 0000000000..807b83051b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-convert.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.plaindate.prototype.until +description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated. +features: [Temporal] +---*/ + +class TZ extends Temporal.TimeZone { + constructor() { super("UTC") } + getOffsetNanosecondsFor() { throw new Test262Error() } +} + +const tz = new TZ(); +const arg = new Temporal.ZonedDateTime(0n, tz); +const instance = new Temporal.PlainDate(1976, 11, 18); + +assert.throws(Test262Error, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..7777ce9c05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-slots.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.plaindate.prototype.until +description: Getters are not called when converting a ZonedDateTime to a PlainDate. +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype); +const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"]; + +for (const property of getters) { + Object.defineProperty(Temporal.ZonedDateTime.prototype, property, { + get() { + actual.push(`get ${property}`); + const value = prototypeDescrs[property].get.call(this); + return { + toString() { + actual.push(`toString ${property}`); + return value.toString(); + }, + valueOf() { + actual.push(`valueOf ${property}`); + return value; + }, + }; + }, + }); +} + +const arg = new Temporal.ZonedDateTime(0n, "UTC"); +const instance = new Temporal.PlainDate(1976, 11, 18); +instance.until(arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..cc57645903 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.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.plaindate.prototype.until +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.until(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..12ee440503 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.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.plaindate.prototype.until +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => date.until(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..31bf9a778f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.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.plaindate.prototype.until +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => date.until(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..5bdc156026 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-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.plaindate.prototype.until +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const date = new Temporal.PlainDate(2000, 5, 2); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => date.until(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/basic.js new file mode 100644 index 0000000000..d2166e9e3e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/basic.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.plaindate.prototype.until +description: Basic tests for until(). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(1969, 7, 24); +const plainDate2 = Temporal.PlainDate.from({ year: 1969, month: 10, day: 5 }); +TemporalHelpers.assertDuration(plainDate.until(plainDate2), 0, 0, 0, /* days = */ 73, 0, 0, 0, 0, 0, 0, "same year"); + +const earlier = new Temporal.PlainDate(1969, 7, 24); +const later = new Temporal.PlainDate(1996, 3, 3); +TemporalHelpers.assertDuration(earlier.until(later), 0, 0, 0, /* days = */ 9719, 0, 0, 0, 0, 0, 0, "different year"); + +TemporalHelpers.assertDuration(plainDate.until({ year: 2019, month: 7, day: 24 }), 0, 0, 0, /* days = */ 18262, 0, 0, 0, 0, 0, 0, "option bag"); +TemporalHelpers.assertDuration(plainDate.until("2019-07-24"), 0, 0, 0, /* days = */ 18262, 0, 0, 0, 0, 0, 0, "string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/branding.js new file mode 100644 index 0000000000..2625e235f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const until = Temporal.PlainDate.prototype.until; + +assert.sameValue(typeof until, "function"); + +const args = [new Temporal.PlainDate(2022, 6, 22)]; + +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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => until.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..400f425860 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.until(new Temporal.PlainDate(2001, 6, 13)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/builtin.js new file mode 100644 index 0000000000..d65f2e5af7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.until), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.until), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.until), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.until.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..6b72eabd28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateadd-called-with-plaindate-instance.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.plaindate.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.PlainDate(1970, 1, 1, calendar); +calendar.specificPlainDate = instance; +instance.until(new Temporal.PlainDate(2000, 5, 2, calendar), { smallestUnit: "month" }); +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/PlainDate/prototype/until/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..c4455c2f1e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDate(2000, 5, 2, calendar); +instance.until({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..2945cae16d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, calendar); +const argument = new Temporal.PlainDate(2022, 6, 14, calendar); +instance.until(argument, { largestUnit: "months" }); +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/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..7a7f9d92f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.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.plaindate.prototype.until +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plaindate.prototype.until steps 12–13: + 13. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _largestUnit_). + 14. Let _result_ be ? CalendarDateUntil(_temporalDate_.[[Calendar]], _temporalDate_, _other_, _untilOptions_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainDate(2000, 5, 2, calendar); + const later = new Temporal.PlainDate(2001, 6, 3, calendar); + earlier.until(later, { largestUnit }); + }, + { + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-fields-iterable.js new file mode 100644 index 0000000000..b77217dd0c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-fields-iterable.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.plaindate.prototype.until +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar1 = TemporalHelpers.calendarFieldsIterable(); +const date = new Temporal.PlainDate(2000, 5, 2, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +date.until({ year: 2005, month: 6, day: 2, 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/PlainDate/prototype/until/calendar-id-match.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-id-match.js new file mode 100644 index 0000000000..ddff8dae6c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-id-match.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.plaindate.prototype.until +description: Calculation is performed if calendars' toString results match +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +class Calendar1 extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + toString() { + return "A"; + } +} +class Calendar2 extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + toString() { + return "A"; + } +} + +const plainDate1 = new Temporal.PlainDate(2000, 1, 1, new Calendar1()); +const plainDate2 = new Temporal.PlainDate(2000, 1, 2, new Calendar2()); +TemporalHelpers.assertDuration(plainDate1.until(plainDate2), 0, 0, 0, /* days = */ 1, 0, 0, 0, 0, 0, 0); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js new file mode 100644 index 0000000000..632e9d69e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-invalid-return.js @@ -0,0 +1,42 @@ +// |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.plaindate.prototype.until +description: Throw when the returned value from the calendar's dateUntil method is not a Duration. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + dateUntil() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.Duration, "Temporal.Duration"], + [Temporal.Duration.prototype, "Temporal.Duration.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws( + TypeError, () => plainDate.until("2022-06-20", { largestUnit: "years" }), + `Expected error with ${description}` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-mismatch.js new file mode 100644 index 0000000000..65be788ce3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-mismatch.js @@ -0,0 +1,62 @@ +// |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.plaindate.prototype.until +description: RangeError thrown if calendars' id properties do not match +features: [Temporal] +---*/ + +const calendar1 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "A", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const calendar2 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "B", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +const plainDate1 = new Temporal.PlainDate(2000, 1, 1, calendar1); +const plainDate2 = new Temporal.PlainDate(2000, 1, 1, calendar2); +assert.throws(RangeError, () => plainDate1.until(plainDate2)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/calendar-temporal-object.js new file mode 100644 index 0000000000..4f03a0b94d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindate.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDate(_other_). + sec-temporal-totemporaldate step 2.c: + c. 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 date = new Temporal.PlainDate(2000, 5, 2, temporalObject); + date.until({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/custom.js new file mode 100644 index 0000000000..c2d9d2cb82 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/custom.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.plaindate.prototype.until +description: Basic tests with custom calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const result = new Temporal.Duration(1, 3, 5, 7, 9); +const options = { largestUnit: "years" }; +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateUntil(...args) { + ++calls; + assert.sameValue(args.length, 3, "Three arguments"); + assert.sameValue(args[0], plainDate, "First argument"); + assert.sameValue(args[1], other, "Second argument"); + assert.sameValue(args[2].largestUnit, "year", "Third argument: largestUnit"); + return result; + } +} +const calendar = new CustomCalendar(); +const plainDate = new Temporal.PlainDate(1976, 11, 18, calendar); +const other = new Temporal.PlainDate(2022, 6, 20, calendar); +TemporalHelpers.assertDuration(plainDate.until(other, options), + 1, 3, 5, 7, 0, 0, 0, 0, 0, 0, "result"); +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-month.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-month.js new file mode 100644 index 0000000000..72ff38ca21 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-month.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.plaindate.prototype.until +description: until() should take length of month into account. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate1 = Temporal.PlainDate.from("2019-01-01"); +const plainDate2 = Temporal.PlainDate.from("2019-02-01"); +const plainDate3 = Temporal.PlainDate.from("2019-03-01"); +TemporalHelpers.assertDuration(plainDate1.until(plainDate2), 0, 0, 0, /* days = */ 31, 0, 0, 0, 0, 0, 0, "January 2019"); +TemporalHelpers.assertDuration(plainDate2.until(plainDate3), 0, 0, 0, /* days = */ 28, 0, 0, 0, 0, 0, 0, "February 2019"); + +const plainDate4 = Temporal.PlainDate.from("2020-02-01"); +const plainDate5 = Temporal.PlainDate.from("2020-03-01"); +TemporalHelpers.assertDuration(plainDate4.until(plainDate5), 0, 0, 0, /* days = */ 29, 0, 0, 0, 0, 0, 0, "February 2020"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-year.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-year.js new file mode 100644 index 0000000000..6ca8c59327 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/days-in-year.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.plaindate.prototype.until +description: until() should take length of year into account. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate1 = Temporal.PlainDate.from("2019-01-01"); +const plainDate2 = Temporal.PlainDate.from("2020-01-01"); +const plainDate3 = Temporal.PlainDate.from("2021-01-01"); +TemporalHelpers.assertDuration(plainDate1.until(plainDate2), 0, 0, 0, /* days = */ 365, 0, 0, 0, 0, 0, 0, "From January 2019"); +TemporalHelpers.assertDuration(plainDate2.until(plainDate3), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "From January 2020"); + +const plainDate4 = Temporal.PlainDate.from("2019-06-01"); +const plainDate5 = Temporal.PlainDate.from("2020-06-01"); +const plainDate6 = Temporal.PlainDate.from("2021-06-01"); +TemporalHelpers.assertDuration(plainDate4.until(plainDate5), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "From June 2019"); +TemporalHelpers.assertDuration(plainDate5.until(plainDate6), 0, 0, 0, /* days = */ 365, 0, 0, 0, 0, 0, 0, "From June 2020"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..6bd0c01f29 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].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/PlainDate/prototype/until/largestunit-default.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.js new file mode 100644 index 0000000000..907df1f977 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-default.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.plaindate.prototype.until +description: Default value for largestUnit option is days +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = Temporal.PlainDate.from("2020-02-01"); +const feb21 = Temporal.PlainDate.from("2021-02-01"); +TemporalHelpers.assertDuration(feb20.until(feb21), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no options"); +TemporalHelpers.assertDuration(feb20.until(feb21, undefined), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined options"); +TemporalHelpers.assertDuration(feb20.until(feb21, {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: undefined }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "undefined largestUnit"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "days" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "days"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "auto" }), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "auto"); +TemporalHelpers.assertDuration(feb20.until(feb21, () => {}), 0, 0, 0, /* days = */ 366, 0, 0, 0, 0, 0, 0, "no largestUnit (function)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.js new file mode 100644 index 0000000000..a8f8812d9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-higher-units.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.plaindate.prototype.until +description: Tests calculations with higher largestUnit than the default of 'days' +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1969, 7, 24); +const later = Temporal.PlainDate.from({ year: 2019, month: 7, day: 24 }); +const duration = date.until(later, { largestUnit: "years" }); +TemporalHelpers.assertDuration(duration, /* years = */ 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, "crossing epoch"); + +const feb20 = Temporal.PlainDate.from("2020-02-01"); +const feb21 = Temporal.PlainDate.from("2021-02-01"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "years" }), /* years = */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, years"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "months" }), 0, /* months = */ 12, 0, 0, 0, 0, 0, 0, 0, 0, "start of February, months"); +TemporalHelpers.assertDuration(feb20.until(feb21, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 2, 0, 0, 0, 0, 0, 0, "start of February, weeks"); + +const lastFeb20 = Temporal.PlainDate.from("2020-02-29"); +const lastFeb21 = Temporal.PlainDate.from("2021-02-28"); +TemporalHelpers.assertDuration(lastFeb20.until(lastFeb21, { largestUnit: "years" }), /* years = */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "end of February, years"); +TemporalHelpers.assertDuration(lastFeb20.until(lastFeb21, { largestUnit: "months" }), 0, /* months = */ 12, 0, 0, 0, 0, 0, 0, 0, 0, "end of February, months"); +TemporalHelpers.assertDuration(lastFeb20.until(lastFeb21, { largestUnit: "weeks" }), 0, 0, /* weeks = */ 52, /* days = */ 1, 0, 0, 0, 0, 0, 0, "end of February, weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.js new file mode 100644 index 0000000000..145b8d3024 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-invalid-string.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.plaindate.prototype.until +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..84769e1877 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-plurals-accepted.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.plaindate.prototype.until +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 12); +const validUnits = [ + "year", + "month", + "week", + "day", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => earlier.until(later, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..91ba76b412 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const units = ["years", "months", "weeks", "days"]; +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/PlainDate/prototype/until/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-undefined.js new file mode 100644 index 0000000000..0b24449663 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-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.plaindate.prototype.until +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); + +const explicit = earlier.until(later, { largestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default largestUnit is day"); +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default largestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/largestunit-wrong-type.js new file mode 100644 index 0000000000..42d56c641e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "year", + (largestUnit) => earlier.until(later, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/length.js new file mode 100644 index 0000000000..31c204731d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/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.plaindate.prototype.until +description: Temporal.PlainDate.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.PlainDate.prototype.until, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/name.js new file mode 100644 index 0000000000..99b7ae2be1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Temporal.PlainDate.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.PlainDate.prototype.until, "name", { + value: "until", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/not-a-constructor.js new file mode 100644 index 0000000000..2d4a6df0d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: > + Temporal.PlainDate.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.PlainDate.prototype.until(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.until), false, + "isConstructor(Temporal.PlainDate.prototype.until)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/options-object.js new file mode 100644 index 0000000000..978d5189f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.until(new Temporal.PlainDate(1976, 11, 18), {}); +TemporalHelpers.assertDuration( + result1, 0, 0, 0, -8566, 0, 0, 0, 0, 0, 0, + "options may be an empty plain object" +); + +const result2 = instance.until(new Temporal.PlainDate(1976, 11, 18), () => {}); +TemporalHelpers.assertDuration( + result2, 0, 0, 0, -8566, 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/PlainDate/prototype/until/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/options-wrong-type.js new file mode 100644 index 0000000000..dd67a3bd6b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainDate(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js new file mode 100644 index 0000000000..427670784a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js @@ -0,0 +1,214 @@ +// |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.plaindate.prototype.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDate + "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.dateFromFields", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "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.dateFromFields", + // 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 actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); + +const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "days", 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); + +// basic order of observable operations with calendar call, without rounding: +instance.until(otherDatePropertyBag, createOptionsObserver({ largestUnit: "years" })); +assert.compareArray(actual, expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", +]), "order of operations"); +actual.splice(0); // clear + +// short-circuit for identical objects: + +const identicalPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.since(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations with identical dates"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 12.d + "call this.calendar.dateAdd", // 12.f + "call this.calendar.dateUntil", // 12.n + "call this.calendar.dateAdd", // 12.x MoveRelativeDate + // (12.r 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(otherDatePropertyBag, 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 otherDatePropertyBagSameMonth = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); +const expectedOpsForYearRoundingSameMonth = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 12.d + "call this.calendar.dateAdd", // 12.f + "call this.calendar.dateAdd", // 12.x MoveRelativeDate + // (12.n not called because months and weeks == 0) + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateUntil" // 9.d +]); +instance.until(otherDatePropertyBagSameMonth, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRoundingSameMonth, "order of operations with smallestUnit = years and no excess months/weeks"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateAdd", // 13.c + "call this.calendar.dateAdd", // 13.e + "call this.calendar.dateAdd", // 13.w MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil" // 10.e +]); +instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + // lookup + "get this.calendar.dateAdd", + "get this.calendar.dateUntil", + // CalendarDateUntil + "call this.calendar.dateUntil", + // RoundDuration + "call this.calendar.dateUntil", // 14.f + "call this.calendar.dateAdd", // 14.p MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 16 + "call this.calendar.dateUntil" // 17 +]); +instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with smallestUnit = weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/prop-desc.js new file mode 100644 index 0000000000..0c230a999e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: The "until" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.until, + "function", + "`typeof PlainDate.prototype.until` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "until", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/round-cross-unit-boundary.js new file mode 100644 index 0000000000..6b15e24902 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2022, 1, 1); +const later = new Temporal.PlainDate(2023, 12, 25); +const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "months", roundingMode: "expand" }); +TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year 11 months balances to 2 years"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-relative.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-relative.js new file mode 100644 index 0000000000..b7b28c9338 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-relative.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.plaindate.prototype.until +description: Should round relative to the receiver. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date1 = Temporal.PlainDate.from("2019-01-01"); +const date2 = Temporal.PlainDate.from("2019-02-15"); + +TemporalHelpers.assertDuration( + date1.until(date2, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ 2, 0, 0, 0, 0, 0, 0, 0, 0); +TemporalHelpers.assertDuration( + date2.until(date1, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ -1, 0, 0, 0, 0, 0, 0, 0, 0); + +const cases = [ + ["2019-03-01", "2019-01-29", 1, 1], + ["2019-01-29", "2019-03-01", -1, -3], + ["2019-03-29", "2019-01-30", 1, 29], + ["2019-01-30", "2019-03-29", -1, -29], + ["2019-03-30", "2019-01-31", 1, 30], + ["2019-01-31", "2019-03-30", -1, -28], + ["2019-03-31", "2019-01-31", 2, 0], + ["2019-01-31", "2019-03-31", -2, 0] +]; +for (const [end, start, months, days] of cases) { + const result = Temporal.PlainDate.from(start).until(end, { largestUnit: "months" }); + TemporalHelpers.assertDuration(result, 0, months, 0, days, 0, 0, 0, 0, 0, 0, `${end} - ${start}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-zero-year-month-week-length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-zero-year-month-week-length.js new file mode 100644 index 0000000000..1d56c472c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/rounding-zero-year-month-week-length.js @@ -0,0 +1,34 @@ +// |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.plaindate.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 d1 = new Temporal.PlainDate(1970, 1, 1, cal); +const d2 = new Temporal.PlainDate(1971, 1, 1, cal); + +assert.throws(RangeError, () => d1.until(d2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => d1.until(d2, { smallestUnit: "months" }), "zero month length handled correctly"); +assert.throws(RangeError, () => d1.until(d2, { smallestUnit: "weeks" }), "zero week length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-nan.js new file mode 100644 index 0000000000..7e68bdd813 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.prototype.until step 11: + 11. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.js new file mode 100644 index 0000000000..349135ad08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.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.plaindate.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.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +const result = earlier.until(later, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, "roundingIncrement 2.5 truncates to 2"); +const result2 = earlier.until(later, { smallestUnit: "days", roundingIncrement: 1e9 + 0.5, roundingMode: "expand" }); +TemporalHelpers.assertDuration(result2, 0, 0, 0, 1e9, 0, 0, 0, 0, 0, 0, "roundingIncrement 1e9 + 0.5 truncates to 1e9"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..26092686df --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); +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/PlainDate/prototype/until/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-undefined.js new file mode 100644 index 0000000000..7670614029 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-undefined.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.plaindate.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.plaindate.prototype.until step 11: + 11. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); + +const explicit = earlier.until(later, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, "default roundingIncrement is 1"); + +// See options-undefined.js for {} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..c2cc289fb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.plaindate.prototype.until step 11: + 11. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, *undefined*, *false*). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2000, 5, 7); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => earlier.until(later, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement.js new file mode 100644 index 0000000000..5a86e247c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingincrement.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.plaindate.prototype.until +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = Temporal.PlainDate.from("2019-01-08"); +const later = Temporal.PlainDate.from("2021-09-07"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }), + /* years = */ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, "years"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "months", roundingIncrement: 10, roundingMode: "halfExpand" }), + 0, /* months = */ 30, 0, 0, 0, 0, 0, 0, 0, 0, "months"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "weeks", roundingIncrement: 12, roundingMode: "halfExpand" }), + 0, 0, /* weeks = */ 144, 0, 0, 0, 0, 0, 0, 0, "weeks"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "days", roundingIncrement: 100, roundingMode: "halfExpand" }), + 0, 0, 0, /* days = */ 1000, 0, 0, 0, 0, 0, 0, "days"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-ceil.js new file mode 100644 index 0000000000..fe40fdd5f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-ceil.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-2]], + ["months", [0, 32], [0, -31]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js new file mode 100644 index 0000000000..d3b3271b50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-floor.js new file mode 100644 index 0000000000..37c8a1c1a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-floor.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [2], [-3]], + ["months", [0, 31], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js new file mode 100644 index 0000000000..55118dd705 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js new file mode 100644 index 0000000000..3b42461cdb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js new file mode 100644 index 0000000000..c5fc068b82 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfFloor.js new file mode 100644 index 0000000000..b4f0c8f767 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfFloor.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..abd790fe34 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfTrunc.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-invalid-string.js new file mode 100644 index 0000000000..7cc40d387e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/until/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-trunc.js new file mode 100644 index 0000000000..43cbe4a1f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-trunc.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.until +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2019, 1, 8); +const later = new Temporal.PlainDate(2021, 9, 7); + +const expected = [ + ["years", [2], [-2]], + ["months", [0, 31], [0, -31]], + ["weeks", [0, 0, 139], [0, 0, -139]], + ["days", [0, 0, 0, 973], [0, 0, 0, -973]], +]; + +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/PlainDate/prototype/until/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-undefined.js new file mode 100644 index 0000000000..0370a2e95a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 1, 1); + +const later1 = new Temporal.PlainDate(2005, 2, 20); +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.PlainDate(2005, 12, 15); +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/PlainDate/prototype/until/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/roundingmode-wrong-type.js new file mode 100644 index 0000000000..0c95403f84 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/until/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/until/smallestunit-higher-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-higher-units.js new file mode 100644 index 0000000000..e6cd7b717a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-higher-units.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.plaindate.prototype.until +description: Tests calculations with higher smallestUnit than the default of "days" +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = Temporal.PlainDate.from("2019-01-08"); +const later = Temporal.PlainDate.from("2021-09-07"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "years", roundingMode: "halfExpand" }), + /* years = */ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, "years"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, /* months = */ 32, 0, 0, 0, 0, 0, 0, 0, 0, "months"); + +TemporalHelpers.assertDuration( + earlier.until(later, { smallestUnit: "weeks", roundingMode: "halfExpand" }), + 0, 0, /* weeks = */ 139, 0, 0, 0, 0, 0, 0, 0, "weeks"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.js new file mode 100644 index 0000000000..6979d8f13c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-invalid-string.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.plaindate.prototype.until +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +const badValues = [ + "era", + "eraYear", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", + "month\0", + "YEAR", + "eras", + "eraYears", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "months\0", + "YEARS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..75f6d73609 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-plurals-accepted.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.plaindate.prototype.until +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 12); +const validUnits = [ + "year", + "month", + "week", + "day", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => earlier.until(later, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-undefined.js new file mode 100644 index 0000000000..359541c4f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); + +const explicit = earlier.until(later, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default smallestUnit is day"); +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, "default smallestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/smallestunit-wrong-type.js new file mode 100644 index 0000000000..f257997db1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.until +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDate(2000, 5, 2); +const later = new Temporal.PlainDate(2001, 6, 3); +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/PlainDate/prototype/until/weeks-months.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/weeks-months.js new file mode 100644 index 0000000000..54dbd17bc1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/weeks-months.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.plaindate.prototype.until +description: until() should not return weeks and months together. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(1969, 7, 24); +const laterDate = new Temporal.PlainDate(1969, 9, 4); +TemporalHelpers.assertDuration(date.until(laterDate, { largestUnit: "weeks" }), + 0, 0, /* weeks = */ 6, 0, 0, 0, 0, 0, 0, 0, "weeks"); +TemporalHelpers.assertDuration(date.until(laterDate, { largestUnit: "months" }), + 0, /* months = */ 1, 0, 11, 0, 0, 0, 0, 0, 0, "months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/year-zero.js new file mode 100644 index 0000000000..f92ca0a5e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/until/year-zero.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.plaindate.prototype.until +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-10-31", + "-000000-10-31T00:45", + "-000000-10-31T00:45+01:00", + "-000000-10-31T00:45+00:00[UTC]", +]; +const instance = new Temporal.PlainDate(2000, 5, 2); +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/PlainDate/prototype/valueOf/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/basic.js new file mode 100644 index 0000000000..3b8a525f93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/basic.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.plaindate.prototype.valueof +description: Basic tests for valueOf(). +features: [Temporal] +---*/ + +const plainDate = Temporal.PlainDate.from("1963-02-13"); +const plainDate2 = Temporal.PlainDate.from("1963-02-13"); + +assert.throws(TypeError, () => plainDate.valueOf(), "valueOf"); +assert.throws(TypeError, () => plainDate < plainDate, "<"); +assert.throws(TypeError, () => plainDate <= plainDate, "<="); +assert.throws(TypeError, () => plainDate > plainDate, ">"); +assert.throws(TypeError, () => plainDate >= plainDate, ">="); +assert.sameValue(plainDate === plainDate, true, "==="); +assert.sameValue(plainDate === plainDate2, false, "==="); +assert.sameValue(plainDate !== plainDate, false, "!=="); +assert.sameValue(plainDate !== plainDate2, true, "!=="); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/branding.js new file mode 100644 index 0000000000..f3d9029747 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const valueOf = Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => valueOf.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/builtin.js new file mode 100644 index 0000000000..04ce6abb81 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.valueOf), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.valueOf), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.valueOf), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.valueOf.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/length.js new file mode 100644 index 0000000000..3460276c29 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: Temporal.PlainDate.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.PlainDate.prototype.valueOf, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/name.js new file mode 100644 index 0000000000..a42c0be477 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: Temporal.PlainDate.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.PlainDate.prototype.valueOf, "name", { + value: "valueOf", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/not-a-constructor.js new file mode 100644 index 0000000000..20de55f8c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: > + Temporal.PlainDate.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.PlainDate.prototype.valueOf(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.valueOf), false, + "isConstructor(Temporal.PlainDate.prototype.valueOf)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/prop-desc.js new file mode 100644 index 0000000000..fc586ef792 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.valueof +description: The "valueOf" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.valueOf, + "function", + "`typeof PlainDate.prototype.valueOf` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "valueOf", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/valueOf/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/weekOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/basic.js new file mode 100644 index 0000000000..0e60fc7e81 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/basic.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-get-temporal.plaindate.prototype.weekofyear +description: Basic tests for weekOfYear(). +features: [Temporal] +---*/ + +for (let i = 29; i <= 31; ++i) { + const plainDate = new Temporal.PlainDate(1975, 12, i); + assert.sameValue(plainDate.weekOfYear, 1, `${plainDate} should be in week 1`); +} +for (let i = 1; i <= 4; ++i) { + const plainDate = new Temporal.PlainDate(1976, 1, i); + assert.sameValue(plainDate.weekOfYear, 1, `${plainDate} should be in week 1`); +} +for (let i = 5; i <= 11; ++i) { + const plainDate = new Temporal.PlainDate(1976, 1, i); + assert.sameValue(plainDate.weekOfYear, 2, `${plainDate} should be in week 2`); +} +for (let i = 20; i <= 26; ++i) { + const plainDate = new Temporal.PlainDate(1976, 12, i); + assert.sameValue(plainDate.weekOfYear, 52, `${plainDate} should be in week 52`); +} +for (let i = 27; i <= 31; ++i) { + const plainDate = new Temporal.PlainDate(1976, 12, i); + assert.sameValue(plainDate.weekOfYear, 53, `${plainDate} should be in week 53`); +} +for (let i = 1; i <= 2; ++i) { + const plainDate = new Temporal.PlainDate(1977, 1, i); + assert.sameValue(plainDate.weekOfYear, 53, `${plainDate} should be in week 53`); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/branding.js new file mode 100644 index 0000000000..cb26e7db4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/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-get-temporal.plaindate.prototype.weekofyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const weekOfYear = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "weekOfYear").get; + +assert.sameValue(typeof weekOfYear, "function"); + +assert.throws(TypeError, () => weekOfYear.call(undefined), "undefined"); +assert.throws(TypeError, () => weekOfYear.call(null), "null"); +assert.throws(TypeError, () => weekOfYear.call(true), "true"); +assert.throws(TypeError, () => weekOfYear.call(""), "empty string"); +assert.throws(TypeError, () => weekOfYear.call(Symbol()), "symbol"); +assert.throws(TypeError, () => weekOfYear.call(1), "1"); +assert.throws(TypeError, () => weekOfYear.call({}), "plain object"); +assert.throws(TypeError, () => weekOfYear.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => weekOfYear.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..7a8e2479c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/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.plaindate.prototype.weekofyear +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 weekOfYearOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "weekOfYear"); +Object.defineProperty(Temporal.Calendar.prototype, "weekOfYear", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("weekOfYear should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.weekOfYear; + +Object.defineProperty(Temporal.Calendar.prototype, "weekOfYear", weekOfYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/custom.js new file mode 100644 index 0000000000..1604da720c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/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.plaindate.prototype.weekofyear +description: Custom calendar tests for weekOfYear(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + weekOfYear(...args) { + ++calls; + assert.compareArray(args, [pd], "weekOfYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.weekOfYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/prop-desc.js new file mode 100644 index 0000000000..b1dde97e11 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.weekofyear +description: The "weekOfYear" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "weekOfYear"); +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/PlainDate/prototype/weekOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/validate-calendar-value.js new file mode 100644 index 0000000000..7836bbff10 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/weekOfYear/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.plaindate.prototype.weekofyear +description: Validate result returned from calendar weekOfYear() 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 { + weekOfYear() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.weekOfYear, `${typeof result} ${String(result)} not converted to positive integer`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/basic.js new file mode 100644 index 0000000000..cf5e85bd1d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/basic.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.plaindate.prototype.with +description: Basic tests for with(). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(1976, 11, 18); + +const withYear = plainDate.with({ year: 2019 }); +TemporalHelpers.assertPlainDate(withYear, 2019, 11, "M11", 18, "with(year)"); + +const withMonth = plainDate.with({ month: 5 }); +TemporalHelpers.assertPlainDate(withMonth, 1976, 5, "M05", 18, "with(month)"); + +const withMonthCode = plainDate.with({ monthCode: 'M05' }); +TemporalHelpers.assertPlainDate(withMonthCode, 1976, 5, "M05", 18, "with(monthCode)"); + +const withDay = plainDate.with({ day: 17 }); +TemporalHelpers.assertPlainDate(withDay, 1976, 11, "M11", 17, "with(day)"); + +const withPlural = plainDate.with({ months: 12, day: 15 }); +TemporalHelpers.assertPlainDate(withPlural, 1976, 11, "M11", 15, "with(plural)"); + +assert.throws(RangeError, () => plainDate.with({ month: 5, monthCode: 'M06' })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/branding.js new file mode 100644 index 0000000000..bd2d266e41 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/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.plaindate.prototype.with +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const with_ = Temporal.PlainDate.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.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => with_.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..4e4d090692 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2023, 5, 2, "iso8601"); +instance.with({ day: 5 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..94beab4fd1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 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.PlainDate(2000, 5, 2, "iso8601"); +instance.with({ year: 2001 }); + +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/PlainDate/prototype/with/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/builtin.js new file mode 100644 index 0000000000..d356db6b7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: > + Tests that Temporal.PlainDate.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.PlainDate.prototype.with), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.with), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.with), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.with.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-fields-iterable.js new file mode 100644 index 0000000000..2fd26bafa7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/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.plaindate.prototype.with +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindate.prototype.with step 9: + 9. 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 = [ + "day", + "month", + "monthCode", + "year", +]; + +const calendar = TemporalHelpers.calendarFieldsIterable(); +const date = new Temporal.PlainDate(2000, 5, 2, calendar); +date.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/PlainDate/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..36242e3577 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +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.PlainDate(2000, 5, 2, calendar); +instance.with({ 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/PlainDate/prototype/with/calendar-invalid-return.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-invalid-return.js new file mode 100644 index 0000000000..9555916651 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-invalid-return.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.with +description: Throw when the returned value from the calendar's dateFromFields method is not a PlainDate. +features: [Temporal] +---*/ + +class CustomCalendar extends Temporal.Calendar { + constructor(value) { + super("iso8601"); + this.value = value; + } + dateFromFields() { + return this.value; + } +} + +const tests = [ + [undefined], + [null, "null"], + [true], + ["2000-05"], + [Symbol()], + [200005], + [200005n], + [{}, "plain object"], + [() => {}, "lambda"], + [Temporal.PlainDate, "Temporal.PlainDate"], + [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype"], +]; +for (const [test, description = typeof test] of tests) { + const plainDate = new Temporal.PlainDate(2000, 5, 2, new CustomCalendar(test)); + assert.throws(TypeError, () => plainDate.with({ year: 1 }), `Expected error with ${description}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-merge-fields-returns-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-merge-fields-returns-primitive.js new file mode 100644 index 0000000000..80de0a1a3d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, calendar); + assert.throws(TypeError, () => instance.with({ year: 2005 }), "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/PlainDate/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..a02da126df --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, calendar); +instance.with({ 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/PlainDate/prototype/with/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..ec53ff16a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.with({day: 15})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js new file mode 100644 index 0000000000..ac83620275 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js @@ -0,0 +1,38 @@ +// |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.plaindate.prototype.with +description: The object returned from mergeFields() is copied before being passed to dateFromFields(). +info: | + sec-temporal.plaindate.prototype.with steps 13–15: + 13. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialDate_). + 14. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»). + 15. Return ? DateFromFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get day", + "get day.valueOf", + "call day.valueOf", + "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 date = new Temporal.PlainDate(2021, 3, 31, calendar); +date.with({ year: 2022 }); + +assert.compareArray(calendar.mergeFieldsReturnOperations, expected, "getters called on mergeFields return"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/copy-properties-not-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/copy-properties-not-undefined.js new file mode 100644 index 0000000000..b7dde1f9af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 plainDate = new Temporal.PlainDate(2006, 1, 24); + +TemporalHelpers.assertPlainDate(plainDate.with({ day: 1, year: undefined }), + 2006, 1, "M01", 1, + "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/PlainDate/prototype/with/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/custom.js new file mode 100644 index 0000000000..6efb016438 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/custom.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.with +description: Basic tests with custom calendar +features: [Temporal] +---*/ + +const result = new Temporal.PlainDate(1920, 5, 3); +const options = { + extra: "property", +}; +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateFromFields(...args) { + ++calls; + assert.sameValue(args.length, 2, "Two arguments"); + assert.sameValue(typeof args[0], "object", "First argument: type"); + assert.sameValue(args[0].day, 18, "First argument: day"); + assert.sameValue(args[0].month, 11, "First argument: month"); + assert.sameValue(args[0].monthCode, "M11", "First argument: monthCode"); + assert.sameValue(args[0].year, 43, "First argument: year"); + assert.notSameValue(args[1], options, "Second argument 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 result; + } +} +const calendar = new CustomCalendar(); +const plainDate = new Temporal.PlainDate(1976, 11, 18, calendar); +assert.sameValue(plainDate.with({ year: 43 }, options), result); +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/duplicate-calendar-fields.js new file mode 100644 index 0000000000..8e1628294d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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'], ['day'], ['month'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const date = new Temporal.PlainDate(2023, 5, 1, calendar); + + assert.throws(RangeError, () => date.with({day: 15})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..aa6e168ea7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].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/PlainDate/prototype/with/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/length.js new file mode 100644 index 0000000000..22beee3de6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: Temporal.PlainDate.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.PlainDate.prototype.with, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/name.js new file mode 100644 index 0000000000..8cc69ee18d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: Temporal.PlainDate.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.PlainDate.prototype.with, "name", { + value: "with", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/not-a-constructor.js new file mode 100644 index 0000000000..c730e54a2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: > + Temporal.PlainDate.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.PlainDate.prototype.with(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.with), false, + "isConstructor(Temporal.PlainDate.prototype.with)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-object.js new file mode 100644 index 0000000000..52ec0f1d8c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: Empty or a function object may be used as options +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(2000, 5, 2); + +const result1 = instance.with({ day: 5 }, {}); +TemporalHelpers.assertPlainDate( + result1, 2000, 5, "M05", 5, + "options may be an empty plain object" +); + +const result2 = instance.with({ day: 5 }, () => {}); +TemporalHelpers.assertPlainDate( + result2, 2000, 5, "M05", 5, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-undefined.js new file mode 100644 index 0000000000..99efdcbf51 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-undefined.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.plaindate.prototype.with +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 2, 2); +const fields = { day: 31 }; + +const explicit = date.with(fields, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = date.with(fields); +assert.sameValue(implicit.month, 2, "default overflow is constrain"); +assert.sameValue(implicit.day, 29, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/options-wrong-type.js new file mode 100644 index 0000000000..ed53fa255e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDate(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js new file mode 100644 index 0000000000..5601354e15 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/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.plaindate.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.dateFromFields", + "get this.calendar.fields", + "get this.calendar.mergeFields", + // CalendarFields + "call this.calendar.fields", + // PrepareTemporalFields on receiver + "get this.calendar.day", + "call this.calendar.day", + "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.day", + "get fields.day.valueOf", + "call fields.day.valueOf", + "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", + // CalendarDateFromFields + "call this.calendar.dateFromFields", + // inside Calendar.p.dateFromFields + "get options.overflow.toString", + "call options.overflow.toString", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, 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", + day: 1.7, +}, "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/PlainDate/prototype/with/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/overflow-invalid-string.js new file mode 100644 index 0000000000..725da2cbff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-isodatefromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.with step 16: + 16. Return ? DateFromFields(_calendar_, _fields_, _options_). +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => date.with({ month: 8 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/overflow-undefined.js new file mode 100644 index 0000000000..52768ac466 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-isodatefromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.with step 16: + 16. Return ? DateFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +const explicit = date.with({ month: 15 }, { overflow: undefined }); +TemporalHelpers.assertPlainDate(explicit, 2000, 12, "M12", 2, "default overflow is constrain"); +const implicit = date.with({ month: 15 }, {}); +TemporalHelpers.assertPlainDate(implicit, 2000, 12, "M12", 2, "default overflow is constrain"); +const fun = date.with({ month: 15 }, () => {}); +TemporalHelpers.assertPlainDate(fun, 2000, 12, "M12", 2, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/overflow-wrong-type.js new file mode 100644 index 0000000000..bc53f043ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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-isodatefromfields step 2: + 2. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindate.prototype.with step 16: + 16. Return ? DateFromFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const date = new Temporal.PlainDate(2000, 5, 2); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => date.with({ month: 8 }, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDate(result, 2000, 8, "M08", 2, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/plaindatelike-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/plaindatelike-invalid.js new file mode 100644 index 0000000000..4d1e422690 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/plaindatelike-invalid.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.plaindate.prototype.with +description: Throws TypeError on an argument that is not a PlainDate-like property bag +features: [Temporal] +---*/ + +const plainDate = new Temporal.PlainDate(1976, 11, 18); + +const tests = [ + // Step 3. + [undefined], + [null], + [true], + ["2019-05-17"], + ["2019-05-17T12:34"], + ["2019-05-17T12:34Z"], + ["18:05:42.577"], + ["42"], + [Symbol(), "symbol"], + [42, "number"], + [42n, "bigint"], + + // Step 4. + // RejectObjectWithCalendarOrTimeZone step 2. + [Temporal.PlainDate.from("2019-05-17"), "PlainDate"], + [Temporal.PlainDateTime.from("2019-05-17T12:34"), "PlainDateTime"], + [Temporal.PlainMonthDay.from("2019-05-17"), "PlainMonthDay"], + [Temporal.PlainTime.from("12:34"), "PlainTime"], + [Temporal.PlainYearMonth.from("2019-05-17"), "PlainYearMonth"], + [Temporal.ZonedDateTime.from("2019-05-17T12:34Z[UTC]"), "ZonedDateTime"], + // RejectObjectWithCalendarOrTimeZone step 3-4. + [{ year: 2021, calendar: "iso8601" }, "calendar"], + // RejectObjectWithCalendarOrTimeZone step 5-6. + [{ year: 2021, timeZone: "UTC" }, "timeZone"], + + // Step 7. + [{}, "empty object"], + [{ months: 12 }, "only plural property"], + +]; + +for (const [value, message = String(value)] of tests) { + assert.throws(TypeError, () => plainDate.with(value), message); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/prop-desc.js new file mode 100644 index 0000000000..857b8e17a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/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.plaindate.prototype.with +description: The "with" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.with, + "function", + "`typeof PlainDate.prototype.with` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "with", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/proto-in-calendar-fields.js new file mode 100644 index 0000000000..68eef30019 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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 date = new Temporal.PlainDate(2023, 5, 1, calendar); + +assert.throws(RangeError, () => date.with({day: 15})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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/PlainDate/prototype/with/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/with/subclassing-ignored.js new file mode 100644 index 0000000000..65b263f341 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.prototype.with +description: Objects of a subclass are never created as return values for with() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDate, + [2000, 5, 2], + "with", + [{ day: 20 }], + (result) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 20), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/basic.js new file mode 100644 index 0000000000..daafac19f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/basic.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.plaindate.prototype.withcalendar +description: Basic tests for withCalendar(). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDate = Temporal.PlainDate.from("1976-11-18"); +const calendar = Temporal.Calendar.from("iso8601"); + +const objectResult = plainDate.withCalendar(calendar); +assert.notSameValue(objectResult, plainDate, "object: new object"); +TemporalHelpers.assertPlainDate(objectResult, 1976, 11, "M11", 18, "object"); +assert.sameValue(objectResult.getCalendar(), calendar, "object: calendar"); + +const stringResult = plainDate.withCalendar("iso8601"); +assert.notSameValue(stringResult, plainDate, "string: new object"); +TemporalHelpers.assertPlainDate(stringResult, 1976, 11, "M11", 18, "string"); +assert.sameValue(stringResult.getISOFields().calendar, "iso8601", "string: calendar slot stores a string"); + +const originalCalendar = plainDate.getCalendar(); +const sameResult = plainDate.withCalendar(originalCalendar); +assert.notSameValue(sameResult, plainDate, "original: new object"); +TemporalHelpers.assertPlainDate(sameResult, 1976, 11, "M11", 18, "original"); +assert.sameValue(sameResult.getCalendar(), originalCalendar, "original: calendar slot stores and object"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/branding.js new file mode 100644 index 0000000000..b12a12f12d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const withCalendar = Temporal.PlainDate.prototype.withCalendar; + +assert.sameValue(typeof withCalendar, "function"); + +const args = [new Temporal.Calendar("iso8601")]; + +assert.throws(TypeError, () => withCalendar.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => withCalendar.apply(null, args), "null"); +assert.throws(TypeError, () => withCalendar.apply(true, args), "true"); +assert.throws(TypeError, () => withCalendar.apply("", args), "empty string"); +assert.throws(TypeError, () => withCalendar.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => withCalendar.apply(1, args), "1"); +assert.throws(TypeError, () => withCalendar.apply({}, args), "plain object"); +assert.throws(TypeError, () => withCalendar.apply(Temporal.PlainDate, args), "Temporal.PlainDate"); +assert.throws(TypeError, () => withCalendar.apply(Temporal.PlainDate.prototype, args), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..7869dea1f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +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.PlainDate(2000, 5, 2, "iso8601"); +instance.withCalendar("iso8601"); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/builtin.js new file mode 100644 index 0000000000..92c0aab861 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: > + Tests that Temporal.PlainDate.prototype.withCalendar + 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.PlainDate.prototype.withCalendar), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDate.prototype.withCalendar), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDate.prototype.withCalendar), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDate.prototype.withCalendar.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-case-insensitive.js new file mode 100644 index 0000000000..a367f57bf4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-case-insensitive.js @@ -0,0 +1,39 @@ +// |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.plaindate.prototype.withcalendar +description: Calendar names are case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +const arg = "iSo8601"; +const result = instance.withCalendar(arg); +assert.sameValue(result.calendarId, "iso8601", "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-number.js new file mode 100644 index 0000000000..94eb9a3d7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-number.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.plaindate.prototype.withcalendar +description: A number is not allowed to be a calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +const numbers = [ + 1, + -19761118, + 19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.withCalendar(arg), + "A number is not a valid ISO string for Calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string-leap-second.js new file mode 100644 index 0000000000..5c8fc1773b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string-leap-second.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.plaindate.prototype.withcalendar +description: Leap second is a valid ISO string for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +const arg = "2016-12-31T23:59:60"; +const result = instance.withCalendar(arg); +assert.sameValue( + result.calendarId, + "iso8601", + "leap second is a valid ISO string for Calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string.js new file mode 100644 index 0000000000..8fb978666d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-string.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.plaindate.prototype.withcalendar +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +const arg = "iso8601"; + +const result = instance.withCalendar(arg); +assert.sameValue(result.getISOFields().calendar, "iso8601", `Calendar created from string "${arg}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-temporal-object.js new file mode 100644 index 0000000000..31039caed6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-temporal-object.js @@ -0,0 +1,64 @@ +// |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.plaindate.prototype.withcalendar +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 instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + const result = instance.withCalendar(arg); + 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/PlainDate/prototype/withCalendar/calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-wrong-type.js new file mode 100644 index 0000000000..c6184f42b7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/calendar-wrong-type.js @@ -0,0 +1,64 @@ +// |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.plaindate.prototype.withcalendar +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or object for Calendar +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDate(1976, 11, 18, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "replace-me", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +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, + () => instance.withCalendar(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"], +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.withCalendar(arg), `${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/PlainDate/prototype/withCalendar/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/length.js new file mode 100644 index 0000000000..1c0d85af21 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: Temporal.PlainDate.prototype.withCalendar.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.PlainDate.prototype.withCalendar, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/missing-argument.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/missing-argument.js new file mode 100644 index 0000000000..c8d2409041 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/missing-argument.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.plaindate.prototype.withcalendar +description: TypeError thrown when calendar argument not given +features: [Temporal] +---*/ + +const plainDate = Temporal.PlainDate.from("1976-11-18"); +assert.throws(TypeError, () => plainDate.withCalendar(), "missing argument"); +assert.throws(TypeError, () => plainDate.withCalendar(undefined), "undefined argument"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/name.js new file mode 100644 index 0000000000..ff2da63f67 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: Temporal.PlainDate.prototype.withCalendar.name is "withCalendar". +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.PlainDate.prototype.withCalendar, "name", { + value: "withCalendar", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/not-a-constructor.js new file mode 100644 index 0000000000..222f96e84a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: > + Temporal.PlainDate.prototype.withCalendar 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.PlainDate.prototype.withCalendar(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDate.prototype.withCalendar), false, + "isConstructor(Temporal.PlainDate.prototype.withCalendar)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/prop-desc.js new file mode 100644 index 0000000000..3cb792447e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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.plaindate.prototype.withcalendar +description: The "withCalendar" property of Temporal.PlainDate.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDate.prototype.withCalendar, + "function", + "`typeof PlainDate.prototype.withCalendar` is `function`" +); + +verifyProperty(Temporal.PlainDate.prototype, "withCalendar", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/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/PlainDate/prototype/withCalendar/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/subclassing-ignored.js new file mode 100644 index 0000000000..c188e3fe7a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/withCalendar/subclassing-ignored.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.plaindate.prototype.withcalendar +description: Objects of a subclass are never created as return values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const customCalendar = { + era() { return undefined; }, + eraYear() { return undefined; }, + year() { return 1900; }, + month() { return 2; }, + monthCode() { return "M02"; }, + day() { return 5; }, + id: "custom-calendar", + toString() { return "custom-calendar"; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDate, + [2000, 5, 2], + "withCalendar", + [customCalendar], + (result) => { + TemporalHelpers.assertPlainDate(result, 1900, 2, "M02", 5); + assert.sameValue(result.getCalendar(), customCalendar, "calendar result"); + }, +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/branding.js new file mode 100644 index 0000000000..f41cf4a738 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/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-get-temporal.plaindate.prototype.year +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const year = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => year.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..c17301105f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(2000, 5, 2, "iso8601"); +instance.year; + +Object.defineProperty(Temporal.Calendar.prototype, "year", yearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/custom.js new file mode 100644 index 0000000000..a333cff4e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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, [pd], "year arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.year; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/prop-desc.js new file mode 100644 index 0000000000..45c773b912 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/prop-desc.js @@ -0,0 +1,17 @@ +// |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-get-temporal.plaindate.prototype.year +description: The "year" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.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/PlainDate/prototype/year/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/year/validate-calendar-value.js new file mode 100644 index 0000000000..cf014e9017 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate.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.PlainDate(1981, 12, 15, 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.PlainDate(1981, 12, 15, calendar); + assert.sameValue(instance.year, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/basic.js new file mode 100644 index 0000000000..f5ef96ddb5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/basic.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-get-temporal.plaindate.prototype.yearofweek +description: Basic tests for yearOfWeek(). +features: [Temporal] +---*/ + +for (let i = 29; i <= 31; ++i) { + const plainDate = new Temporal.PlainDate(1975, 12, i); + assert.sameValue(plainDate.yearOfWeek, 1976, `${plainDate} should be in yearOfWeek 1976`); +} +for (let i = 1; i <= 11; ++i) { + const plainDate = new Temporal.PlainDate(1976, 1, i); + assert.sameValue(plainDate.yearOfWeek, 1976, `${plainDate} should be in yearOfWeek 1976`); +} +for (let i = 20; i <= 31; ++i) { + const plainDate = new Temporal.PlainDate(1976, 12, i); + assert.sameValue(plainDate.yearOfWeek, 1976, `${plainDate} should be in yearOfWeek 1976`); +} +for (let i = 1; i <= 2; ++i) { + const plainDate = new Temporal.PlainDate(1977, 1, i); + assert.sameValue(plainDate.yearOfWeek, 1976, `${plainDate} should be in yearOfWeek 1976`); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/branding.js new file mode 100644 index 0000000000..6ade02cfdd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/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.plaindate.prototype.yearofweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const yearOfWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "yearOfWeek").get; + +assert.sameValue(typeof yearOfWeek, "function"); + +assert.throws(TypeError, () => yearOfWeek.call(undefined), "undefined"); +assert.throws(TypeError, () => yearOfWeek.call(null), "null"); +assert.throws(TypeError, () => yearOfWeek.call(true), "true"); +assert.throws(TypeError, () => yearOfWeek.call(""), "empty string"); +assert.throws(TypeError, () => yearOfWeek.call(Symbol()), "symbol"); +assert.throws(TypeError, () => yearOfWeek.call(1), "1"); +assert.throws(TypeError, () => yearOfWeek.call({}), "plain object"); +assert.throws(TypeError, () => yearOfWeek.call(Temporal.PlainDate), "Temporal.PlainDate"); +assert.throws(TypeError, () => yearOfWeek.call(Temporal.PlainDate.prototype), "Temporal.PlainDate.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..e9894eacf6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/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.plaindate.prototype.yearofweek +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 yearOfWeekOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "yearOfWeek"); +Object.defineProperty(Temporal.Calendar.prototype, "yearOfWeek", { + configurable: true, + enumerable: false, + get() { + TemporalHelpers.assertUnreachable("yearOfWeek should not be looked up"); + }, +}); + +const instance = new Temporal.PlainDate(2000, 5, 2, "iso8601"); +instance.yearOfWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "yearOfWeek", yearOfWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/custom.js new file mode 100644 index 0000000000..bbcec99fa4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/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.plaindate.prototype.yearofweek +description: Custom calendar tests for yearOfWeek(). +includes: [compareArray.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + yearOfWeek(...args) { + ++calls; + assert.compareArray(args, [pd], "yearOfWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pd = new Temporal.PlainDate(1830, 8, 25, calendar); +const result = pd.yearOfWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/prop-desc.js new file mode 100644 index 0000000000..1e0463d2c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/prop-desc.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-get-temporal.plaindate.prototype.yearofweek +description: The "yearOfWeek" property of Temporal.PlainDate.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDate.prototype, "yearOfWeek"); +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/PlainDate/prototype/yearOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js new file mode 100644 index 0000000000..ec291bd0ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.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-get-temporal.plaindate.prototype.yearofweek +description: Validate result returned from calendar yearOfWeek() 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], + [NaN, RangeError], + ["7", TypeError], + ["7.5", TypeError], + [{valueOf() { return 7; }}, TypeError], +]; + +badResults.forEach(([result, error]) => { + const calendar = new class extends Temporal.Calendar { + yearOfWeek() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.throws(error, () => instance.yearOfWeek, `${typeof result} ${String(result)} not converted to integer`); +}); + +const preservedResults = [ + -7, +]; + +preservedResults.forEach(result => { + const calendar = new class extends Temporal.Calendar { + yearOfWeek() { + return result; + } + }("iso8601"); + const instance = new Temporal.PlainDate(1981, 12, 15, calendar); + assert.sameValue(instance.yearOfWeek, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDate/subclass.js b/js/src/tests/test262/built-ins/Temporal/PlainDate/subclass.js new file mode 100644 index 0000000000..a268bb672d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDate/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.plaindate +description: Test for Temporal.PlainDate subclassing. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +class CustomPlainDate extends Temporal.PlainDate { +} + +const instance = new CustomPlainDate(2000, 5, 2); +TemporalHelpers.assertPlainDate(instance, 2000, 5, "M05", 2); +assert.sameValue(Object.getPrototypeOf(instance), CustomPlainDate.prototype, "Instance of CustomPlainDate"); +assert(instance instanceof CustomPlainDate, "Instance of CustomPlainDate"); +assert(instance instanceof Temporal.PlainDate, "Instance of Temporal.PlainDate"); + +reportCompare(0, 0); |