diff options
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype')
844 files changed, 23793 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/ambiguous-date.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/ambiguous-date.js new file mode 100644 index 0000000000..d05823e739 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/ambiguous-date.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.plaindatetime.prototype.add +description: Ambiguous addition is handled according to the overflow option +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ months: 1 }), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "constrain when ambiguous result (overflow options not supplied)" +); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ months: 1 }, { overflow: "constrain" }), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "constrain when ambiguous result (overflow options supplied)" +); + +assert.throws( + RangeError, + () => jan31.add({ months: 1 }, { overflow: "reject" }), + "throw when ambiguous result with reject" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration-max.js new file mode 100644 index 0000000000..9093b72e2d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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.assertPlainDateTime(result, 275760, 9, "M09", 13, 23, 59, 59, 999, 999, 999, `operation succeeds with ${descr}`); +} + +const minCases = [ + ["-P273790Y8M11DT23H59M59.999999999S", "string with min years"], + [{ years: -273790, months: -8, days: -11, nanoseconds: -86399999999999 }, "property bag with min years"], + ["-P3285488M11DT23H59M59.999999999S", "string with min months"], + [{ months: -3285488, days: -11, 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.add(arg); + TemporalHelpers.assertPlainDateTime(result, -271821, 4, "M04", 19, 0, 0, 0, 0, 0, 1, `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration-out-of-range.js new file mode 100644 index 0000000000..19e7edbb84 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/add/argument-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration.js new file mode 100644 index 0000000000..0a7bab206c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-duration.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.plaindatetime.prototype.add +description: Duration object arguments are handled +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.add(Temporal.Duration.from("P1MT1S")), + 2020, 2, "M02", 29, 15, 0, 1, 0, 0, 0, + "Duration argument" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-invalid-property.js new file mode 100644 index 0000000000..19f1fe193a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +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/PlainDateTime/prototype/add/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-mixed-sign.js new file mode 100644 index 0000000000..c2d45bd77d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +["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/PlainDateTime/prototype/add/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-not-object.js new file mode 100644 index 0000000000..cd5eb71e7d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Passing a primitive other than string to add() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +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/PlainDateTime/prototype/add/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-singular-properties.js new file mode 100644 index 0000000000..9ceaeb21c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +[ + { 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/PlainDateTime/prototype/add/argument-string-fractional-units-rounding-mode.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string-fractional-units-rounding-mode.js new file mode 100644 index 0000000000..cd03de8f67 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string-fractional-units-rounding-mode.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.plaindatetime.prototype.add +description: Strings with fractional duration units are rounded with the correct rounding mode +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2); + +TemporalHelpers.assertPlainDateTime(datetime.add("PT1.03125H"), 2000, 5, "M05", 2, 1, 1, 52, 500, 0, 0, + "positive fractional units rounded with correct rounding mode"); +TemporalHelpers.assertPlainDateTime(datetime.add("-PT1.03125H"), 2000, 5, "M05", 1, 22, 58, 7, 500, 0, 0, + "negative fractional units rounded with correct rounding mode"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..56f8979c29 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2); + +const resultHours = instance.add("-PT24.567890123H"); +TemporalHelpers.assertPlainDateTime(resultHours, 2000, 4, "M04", 30, 23, 25, 55, 595, 557, 200, "negative fractional hours"); + +const resultMinutes = instance.add("-PT1440.567890123M"); +TemporalHelpers.assertPlainDateTime(resultMinutes, 2000, 4, "M04", 30, 23, 59, 25, 926, 592, 620, "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-string.js new file mode 100644 index 0000000000..e2cd1bde41 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); +const result = instance.add("P3D"); +TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 5, 0, 34, 56, 987, 654, 321); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/balance-negative-time-units.js new file mode 100644 index 0000000000..cfc9691634 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/balance-negative-time-units.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: Negative time fields are balanced upwards +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-addtime step 8: + 8. Return ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_). + sec-temporal-adddatetime step 1: + 1. Let _timeResult_ be ? AddTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). + sec-temporal.plaindatetime.prototype.add step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1996, 5, 2, 1, 1, 1, 1, 1, 1); + +const result1 = datetime.add(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result1, 1996, 5, "M05", 2, 1, 1, 1, 1, 0, 999, "nanoseconds balance"); + +const result2 = datetime.add(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result2, 1996, 5, "M05", 2, 1, 1, 1, 0, 999, 1, "microseconds balance"); + +const result3 = datetime.add(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result3, 1996, 5, "M05", 2, 1, 1, 0, 999, 1, 1, "milliseconds balance"); + +const result4 = datetime.add(new Temporal.Duration(0, 0, 0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result4, 1996, 5, "M05", 2, 1, 0, 59, 1, 1, 1, "seconds balance"); + +const result5 = datetime.add(new Temporal.Duration(0, 0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result5, 1996, 5, "M05", 2, 0, 59, 1, 1, 1, 1, "minutes balance"); + +const result6 = datetime.add(new Temporal.Duration(0, 0, 0, 0, -2)); +TemporalHelpers.assertPlainDateTime(result6, 1996, 5, "M05", 1, 23, 1, 1, 1, 1, 1, "hours balance"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/branding.js new file mode 100644 index 0000000000..7c97373b75 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const add = Temporal.PlainDateTime.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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => add.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..90cd85ab31 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "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/PlainDateTime/prototype/add/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/builtin.js new file mode 100644 index 0000000000..b095e5d926 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.add), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.add), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.add), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.add.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/calendar-dateadd.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/calendar-dateadd.js new file mode 100644 index 0000000000..5870fac724 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/calendar-dateadd.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: PlainDateTime.prototype.add should call dateAdd with the appropriate values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(plainDate, duration, options) { + ++calls; + TemporalHelpers.assertPlainDate(plainDate, 2020, 3, "M03", 14, "plainDate argument"); + TemporalHelpers.assertDuration(duration, 0, 10, 0, 1, 0, 0, 0, 0, 0, 0, "duration argument"); + assert.sameValue(typeof options, "object", "options argument: type"); + assert.sameValue(Object.getPrototypeOf(options), null, "options argument: prototype"); + return super.dateAdd(plainDate, duration, options); + } +} + +const plainDateTime = new Temporal.PlainDateTime(2020, 3, 14, 12, 34, 56, 987, 654, 321, new CustomCalendar()); +const result = plainDateTime.add({ months: 10, hours: 14 }); +TemporalHelpers.assertPlainDateTime(result, 2021, 1, "M01", 15, 2, 34, 56, 987, 654, 321); +assert.sameValue(calls, 1, "should have called dateAdd"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/hour-overflow.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/hour-overflow.js new file mode 100644 index 0000000000..4d6b28f57e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/hour-overflow.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.plaindatetime.prototype.add +description: Testing overflow hours (adding hours that push one to the next/previous day) +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const earlier = new Temporal.PlainDateTime(2020, 5, 31, 23, 12, 38, 271, 986, 102); + +TemporalHelpers.assertPlainDateTime( + earlier.add({ hours: 2 }), + 2020, 6, "M06", 1, 1, 12, 38, 271, 986, 102, + "hours overflow (push to next day)" +); + +const later = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); + +TemporalHelpers.assertPlainDateTime( + later.add({ hours: -12 }), + 2019, 10, "M10", 28, 22, 46, 38, 271, 986, 102, + "hours overflow (push to previous day)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..d9e9e8ce14 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.PlainDateTime.prototype.add throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plaindatetime.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +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/PlainDateTime/prototype/add/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/length.js new file mode 100644 index 0000000000..97c4956693 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.add, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/limits.js new file mode 100644 index 0000000000..6c9178f9e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/limits.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: Checking limits of representable PlainDateTime +features: [Temporal] +---*/ + +const min = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1); +const max = new Temporal.PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999); + +["reject", "constrain"].forEach((overflow) => { + assert.throws( + RangeError, + () => max.add({ nanoseconds: 1 }, { overflow }), + `adding 1 nanosecond beyond maximum limit (overflow = ${overflow})` + ); + assert.throws( + RangeError, + () => min.add({ nanoseconds: -1 }, { overflow }), + `adding -1 nanosecond beyond minimum limit (overflow = ${overflow})` + ); + +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/name.js new file mode 100644 index 0000000000..5e3bad4a9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.add, "name", { + value: "add", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/negative-duration.js new file mode 100644 index 0000000000..826224ef34 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/negative-duration.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.plaindatetime.prototype.add +description: Negative durations can be supplied +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ minutes: -30 }), + 2020, 1, "M01", 31, 14, 30, 0, 0, 0, 0, + "negative minutes" +); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ seconds: -30 }), + 2020, 1, "M01", 31, 14, 59, 30, 0, 0, 0, + "negative seconds" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..97b08ed520 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.PlainDateTime.prototype.add throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plaindatetime.prototype.add +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +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/PlainDateTime/prototype/add/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..24ce0d5391 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +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/PlainDateTime/prototype/add/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/not-a-constructor.js new file mode 100644 index 0000000000..13c3ca718d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.add(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.add), false, + "isConstructor(Temporal.PlainDateTime.prototype.add)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-empty.js new file mode 100644 index 0000000000..e45efaaaae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-empty.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.plaindatetime.prototype.add +description: Verify that undefined options are handled correctly. +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ months: 1 }, {}), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "options may be empty object" +); + +TemporalHelpers.assertPlainDateTime( + jan31.add({ months: 1 }, () => {}), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "options may be function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-invalid.js new file mode 100644 index 0000000000..31a98f2787 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-invalid.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.plaindatetime.prototype.add +description: Various invalid (wrong type) values for options argument +features: [Temporal, Symbol] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +const badOptions = [null, 1, 'hello', true, Symbol('foo'), 1n]; + +badOptions.forEach((bad) => { + assert.throws( + TypeError, + () => jan31.add({ years: 1 }, bad), + `invalid options (${typeof bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-undefined.js new file mode 100644 index 0000000000..410972a985 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 1, 31, 12, 34, 56, 987, 654, 321); +const duration = { months: 1 }; + +const explicit = datetime.add(duration, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = datetime.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/PlainDateTime/prototype/add/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/options-wrong-type.js new file mode 100644 index 0000000000..30da2b6095 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.add({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/order-of-operations.js new file mode 100644 index 0000000000..11024f653b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/order-of-operations.js @@ -0,0 +1,127 @@ +// |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.plaindatetime.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", + // AddDateTime -> 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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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", + // AddDateTime -> 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/PlainDateTime/prototype/add/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js new file mode 100644 index 0000000000..e45665d393 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-invalid-string.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.add step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); +const duration = new Temporal.Duration(3, 3, 0, 3, 3); + + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => datetime.add({ months: 1 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-undefined.js new file mode 100644 index 0000000000..d874734c28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.add step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 31, 12); +const duration = new Temporal.Duration(3, 1); + +const explicit = datetime.add(duration, { overflow: undefined }); +TemporalHelpers.assertPlainDateTime(explicit, 2003, 6, "M06", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain"); +const implicit = datetime.add(duration, {}); +TemporalHelpers.assertPlainDateTime(implicit, 2003, 6, "M06", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-wrong-type.js new file mode 100644 index 0000000000..f9be928b8d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/overflow-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.plaindatetime.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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.add step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]], _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); +const duration = new Temporal.Duration(3, 3, 0, 3, 3); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => datetime.add(duration, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 2003, 8, "M08", 5, 15, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/prop-desc.js new file mode 100644 index 0000000000..6934b827f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.add +description: The "add" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.add, + "function", + "`typeof PlainDateTime.prototype.add` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "add", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/add/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/subclassing-ignored.js new file mode 100644 index 0000000000..8e42154531 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.add +description: Objects of a subclass are never created as return values for add() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "add", + [{ nanoseconds: 1 }], + (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 322), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/branding.js new file mode 100644 index 0000000000..f6208fa688 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.calendarid +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const calendarId = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => calendarId.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..51cdaea3c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.calendarId; + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/prop-desc.js new file mode 100644 index 0000000000..7b190782ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.calendarid +description: The "calendarId" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/calendarId/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/calendarId/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/constructor.js new file mode 100644 index 0000000000..f9ba1858d6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.constructor +description: Test for Temporal.PlainDateTime.prototype.constructor. +info: The initial value of Temporal.PlainDateTime.prototype.constructor is %Temporal.PlainDateTime%. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainDateTime.prototype, "constructor", { + value: Temporal.PlainDateTime, + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/branding.js new file mode 100644 index 0000000000..ecf7156ae5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/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.plaindatetime.prototype.day +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const day = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => day.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..d2a691a269 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.day; + +Object.defineProperty(Temporal.Calendar.prototype, "day", dayOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/custom.js new file mode 100644 index 0000000000..c06146b056 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "day arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.day; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/prop-desc.js new file mode 100644 index 0000000000..d2a6f079e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/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.plaindatetime.prototype.day +description: The "day" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/day/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/day/validate-calendar-value.js new file mode 100644 index 0000000000..f029012c5d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/dayOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/basic.js new file mode 100644 index 0000000000..29c5ae481c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/basic.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-get-temporal.plaindatetime.prototype.dayofweek +description: Checking day of week for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +assert.sameValue(datetime.dayOfWeek, 4, "check day of week information"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/branding.js new file mode 100644 index 0000000000..ff2d862576 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/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.plaindatetime.prototype.dayofweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const dayOfWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => dayOfWeek.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..670601adc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.dayOfWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "dayOfWeek", dayOfWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/custom.js new file mode 100644 index 0000000000..4bb559fd3f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "dayOfWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.dayOfWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/prop-desc.js new file mode 100644 index 0000000000..8045da6228 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/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.plaindatetime.prototype.dayofweek +description: The "dayOfWeek" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/dayOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/validate-calendar-value.js new file mode 100644 index 0000000000..2612ef18f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/dayOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/basic.js new file mode 100644 index 0000000000..0cbbe195fe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/basic.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-get-temporal.plaindatetime.prototype.dayofyear +description: Checking day of year for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +assert.sameValue(datetime.dayOfYear, 323, "check day of year information"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/branding.js new file mode 100644 index 0000000000..27970c2b80 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/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.plaindatetime.prototype.dayofyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const dayOfYear = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => dayOfYear.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..51a03fc9a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.dayOfYear; + +Object.defineProperty(Temporal.Calendar.prototype, "dayOfYear", dayOfYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/custom.js new file mode 100644 index 0000000000..589aa29003 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "dayOfYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.dayOfYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/prop-desc.js new file mode 100644 index 0000000000..b0db9e144f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/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.plaindatetime.prototype.dayofyear +description: The "dayOfYear" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/dayOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/dayOfYear/validate-calendar-value.js new file mode 100644 index 0000000000..86dc374962 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/daysInMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/basic.js new file mode 100644 index 0000000000..bfa4e7afc4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.daysinmonth +description: Checking days in month for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDateTime(1976, 2, 18, 15, 23, 30, 123, 456, 789), 29], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789), 30], + [new Temporal.PlainDateTime(1976, 12, 18, 15, 23, 30, 123, 456, 789), 31], + [new Temporal.PlainDateTime(1977, 2, 18, 15, 23, 30, 123, 456, 789), 28], +]; +for (const [plainDateTime, expected] of tests) { + assert.sameValue(plainDateTime.daysInMonth, expected, `${expected} days in the month of ${plainDateTime}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/branding.js new file mode 100644 index 0000000000..df0de408b3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.daysinmonth +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInMonth = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => daysInMonth.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..62e01f3615 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.daysInMonth; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInMonth", daysInMonthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/custom.js new file mode 100644 index 0000000000..b5a9807cc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "daysInMonth arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.daysInMonth; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/prop-desc.js new file mode 100644 index 0000000000..3beeb3ffac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.daysinmonth +description: The "daysInMonth" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/daysInMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInMonth/validate-calendar-value.js new file mode 100644 index 0000000000..2ddd63adb8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/daysInWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/basic.js new file mode 100644 index 0000000000..9fa4721d75 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/basic.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-get-temporal.plaindatetime.prototype.daysinweek +description: Checking days in week for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const tests = [ + new Temporal.PlainDateTime(1976, 1, 1, 15, 23, 30, 123, 456, 789), + new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789), + new Temporal.PlainDateTime(1976, 12, 31, 15, 23, 30, 123, 456, 789), +]; +for (const plainDateTime of tests) { + assert.sameValue(plainDateTime.daysInWeek, 7, `Seven days in the week of ${plainDateTime}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/branding.js new file mode 100644 index 0000000000..5983749761 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/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.plaindatetime.prototype.daysinweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => daysInWeek.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..7dec28473b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.daysInWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInWeek", daysInWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/custom.js new file mode 100644 index 0000000000..ce3af6a208 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "daysInWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.daysInWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/prop-desc.js new file mode 100644 index 0000000000..cf29852b48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/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.plaindatetime.prototype.daysinweek +description: The "daysInWeek" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/daysInWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInWeek/validate-calendar-value.js new file mode 100644 index 0000000000..db73c9ca69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/daysInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/basic.js new file mode 100644 index 0000000000..de422d729b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/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.plaindatetime.prototype.daysinyear +description: Checking days in year for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789)).daysInYear, + 366, "leap year"); +assert.sameValue((new Temporal.PlainDateTime(1977, 11, 18, 15, 23, 30, 123, 456, 789)).daysInYear, + 365, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/branding.js new file mode 100644 index 0000000000..3a102e63d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.daysinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const daysInYear = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => daysInYear.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..70cbdd66f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.daysInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "daysInYear", daysInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/custom.js new file mode 100644 index 0000000000..ec28f93a12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "daysInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.daysInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/prop-desc.js new file mode 100644 index 0000000000..54c466d351 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.daysinyear +description: The "daysInYear" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/daysInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/daysInYear/validate-calendar-value.js new file mode 100644 index 0000000000..c6fd25287b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/equals/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..1afe3dc313 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const arg = { year: 2000, month: 5, day: 2, hour: 21, minute: 43, second: 5, calendar: "iso8601" }; +instance.equals(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-number.js new file mode 100644 index 0000000000..bf97cf78d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: A number cannot be used in place of a Temporal.PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.equals(arg), + `A number (${arg}) is not a valid ISO string for PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-object-insufficient-data.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-object-insufficient-data.js new file mode 100644 index 0000000000..cd663443f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-object-insufficient-data.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.plaindatetime.prototype.equals +description: If argument is an object, it must contain sufficient information +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); + +assert.throws( + TypeError, + () => dt.equals({ year: 1976 }), + "object must contain required properties" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-plaindate.js new file mode 100644 index 0000000000..54eb0ee4aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-plaindate.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.plaindatetime.prototype.equals +description: Fast path for converting Temporal.PlainDate to Temporal.PlainDateTime by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.b: + b. If _item_ has an [[InitializedTemporalDate]] internal slot, then + i. Return ? CreateTemporalDateTime(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], 0, 0, 0, 0, 0, 0, _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalPlainDateTimeFastPath((date, calendar) => { + const datetime = new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 0, 0, 0, calendar); + assert(datetime.equals(date)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..d25cf80551 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/equals/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..7ff0a1b655 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Leap second is a valid ISO string for a calendar in a property bag +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/equals/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..e532ba1fb1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/equals/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..9715239429 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/equals/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..ba0f49ec64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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/PlainDateTime/prototype/equals/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..967839b97e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/equals/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..067490424a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-calendar-annotation.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18T15:23[u-ca=iso8601]", "without time zone"], + ["1976-11-18T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["1976-11-18T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["1976-11-18T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["1976-11-18T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/equals/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..f47dbb00ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/equals/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..b83a73f0f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +const validStrings = [ + "1976-11-18T15:23+00:00", + "1976-11-18T15:23+00:00[UTC]", + "1976-11-18T15:23+00:00[!UTC]", + "1976-11-18T15:23-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 PlainDateTime` + ); +} + +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 PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..cd069f5857 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/equals/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..42a7ade474 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/equals/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-time-separators.js new file mode 100644 index 0000000000..bef88b1f4f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18T15:23", "uppercase T"], + ["1976-11-18t15:23", "lowercase T"], + ["1976-11-18 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/equals/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..f1c038171e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-time-zone-annotation.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18T15:23[Asia/Kolkata]", "named, with no offset"], + ["1976-11-18T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["1976-11-18T15:23[+00:00]", "numeric, with no offset"], + ["1976-11-18T15:23[!-02:30]", "numeric, with ! and no offset"], + ["1976-11-18T15:23+00:00[UTC]", "named, with offset"], + ["1976-11-18T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1976-11-18T15:23+00:00[+01:00]", "numeric, with offset"], + ["1976-11-18T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/equals/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..1a128c2671 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-unknown-annotation.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["1976-11-18T15:23[foo=bar]", "alone"], + ["1976-11-18T15:23[UTC][foo=bar]", "with time zone"], + ["1976-11-18T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["1976-11-18T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1976-11-18T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/equals/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..e1efc0c0ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: RangeError thrown if a string with UTC designator is used as a PlainDateTime +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.equals(arg), + "String with UTC designator should not be valid as a PlainDateTime" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..25a644b4ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDateTime +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.PlainDateTime, "Temporal.PlainDateTime, object"], + [Temporal.PlainDateTime.prototype, "Temporal.PlainDateTime.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/PlainDateTime/prototype/equals/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..4e26be85b3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-balance-negative-time-units.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.plaindatetime.prototype.equals +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-totemporaldatetime step 3.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + ... + ii. 1. Return ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ ? ToTemporalDateTime(_other_). +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); + +assert(new Temporal.PlainDateTime(1970, 1, 1, 1, 1, 1, 1, 0, 999).equals(datetime)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..73f5790fea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/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.plaindatetime.prototype.equals +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.PlainDateTime(1969, 7, 24, 16, 50, 35, 0, 0, 1); +const result = instance.equals(datetime); +assert.sameValue(result, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..e02afefd3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.equals(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..b2fe1b47df --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => plain.equals(zoned), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..1570b82c02 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.equals(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..06940015b9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => plain.equals(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/basic.js new file mode 100644 index 0000000000..6788f4f879 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/basic.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.plaindatetime.prototype.equals +description: Checking a typical case (everything defined, no NaNs, nothing throws, etc.) +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const dt2 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt3 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const dt4 = new Temporal.PlainDateTime(2019, 10, 29, 15, 23, 30, 123, 456, 789); +const dt5 = new Temporal.PlainDateTime(1976, 11, 18, 10, 46, 38, 271, 986, 102); + +assert.sameValue(dt1.equals(dt1), true, "equal"); +assert.sameValue(dt1.equals(dt2), false, "unequal"); +assert.sameValue(dt2.equals(dt3), true, "equal with different objects"); +assert.sameValue(dt2.equals(dt4), false, "same date, different time"); +assert.sameValue(dt2.equals(dt5), false, "same time, different date"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/branding.js new file mode 100644 index 0000000000..701540f5a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const equals = Temporal.PlainDateTime.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +const args = [new Temporal.PlainDateTime(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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => equals.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..1c3f13d96d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.equals(new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321)); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/builtin.js new file mode 100644 index 0000000000..f443c49906 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.equals), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.equals), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.equals), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.equals.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js new file mode 100644 index 0000000000..28e8d34147 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-checked.js @@ -0,0 +1,112 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Calendar is taken into account if the ISO data is equal +includes: [compareArray.js,temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; + +function makeCalendar(id, objectName) { + const calendar = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, + }; + TemporalHelpers.observeProperty(actual, calendar, "id", id, objectName); + return calendar; +} + +const calendar1 = makeCalendar("A", "calendar1"); +const calendar2 = makeCalendar("A", "calendar2"); +const calendar3 = makeCalendar("B", "calendar3"); +const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar1); +const dt1b = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar1); +const dt2 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar2); +const dt3 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar3); +actual.splice(0); // disregard the HasProperty checks done in the constructor + +assert.sameValue(dt1.equals(dt1b), true, "same calendar object"); +assert.compareArray(actual, []); + +assert.sameValue(dt1.equals(dt2), true, "same calendar string"); +assert.compareArray(actual, ["get calendar1.id", "get calendar2.id"]); + +actual.splice(0); // empty it for the next check +assert.sameValue(dt1.equals(dt3), false, "different calendar string"); +assert.compareArray(actual, ["get calendar1.id", "get calendar3.id"]); + +const calendar4 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + get id() { TemporalHelpers.assertUnreachable('should not get calendar4.id'); }, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const calendar5 = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + get id() { TemporalHelpers.assertUnreachable('should not get calendar5.id'); }, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const dt4 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar4); +const dt5 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar4); +const dt6 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102, calendar5); +assert.sameValue(dt4.equals(dt5), false, "not equal same calendar"); +assert.sameValue(dt4.equals(dt6), false, "not equal different calendar"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..a6af1e4f24 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/equals/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-fields-iterable.js new file mode 100644 index 0000000000..c8c128aed3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +datetime.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/PlainDateTime/prototype/equals/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/calendar-temporal-object.js new file mode 100644 index 0000000000..3b42636d2d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime 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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, temporalObject); + datetime.equals({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/cast.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/cast.js new file mode 100644 index 0000000000..5ff5d4baf1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/cast.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.plaindatetime.prototype.equals +description: Argument may be cast +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const dt2 = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); + +assert.sameValue( + dt1.equals({ + year: 1976, + month: 11, + day: 18, + hour: 15, + minute: 23, + second: 30, + millisecond: 123, + microsecond: 456, + nanosecond: 789 + }), + true, + "casts argument (plain object, positive)" +); + + +assert.sameValue( + dt2.equals({ year: 1976, month: 11, day: 18, hour: 15 }), + false, + "casts argument (plain object, negative)" +); + +assert.sameValue( + dt1.equals("1976-11-18T15:23:30.123456789"), + true, + "casts argument (string, positive)" +); + +assert.sameValue( + dt2.equals("1976-11-18T15:23:30.123456789"), + false, + "casts argument (string, negative)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..3a444f6002 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/duplicate-calendar-fields.js new file mode 100644 index 0000000000..f8900be8ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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'], ['hour'], ['microsecond'], ['millisecond'], ['minute'], ['month'], ['monthCode'], ['nanosecond'], ['second'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + + assert.throws(RangeError, () => instance.equals(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..ba5cde17c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15); +const base = { year: 2000, month: 5, day: 2, hour: 15, minute: 30, second: 45, millisecond: 987, microsecond: 654, nanosecond: 321 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].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/PlainDateTime/prototype/equals/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/leap-second.js new file mode 100644 index 0000000000..523ab77e2f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/leap-second.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.equals +description: Leap second is a valid ISO string for PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2016, 12, 31, 23, 59, 59); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.equals(arg); +assert.sameValue( + result1, + true, + "leap second is a valid ISO string for PlainDateTime" +); + +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 PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/length.js new file mode 100644 index 0000000000..496ec4fe63 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.equals, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/name.js new file mode 100644 index 0000000000..4903a11e40 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.equals, "name", { + value: "equals", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/not-a-constructor.js new file mode 100644 index 0000000000..ab15972cee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.equals(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.equals), false, + "isConstructor(Temporal.PlainDateTime.prototype.equals)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..f7be4f549c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: The "equals" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.equals, + "function", + "`typeof PlainDateTime.prototype.equals` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/proto-in-calendar-fields.js new file mode 100644 index 0000000000..fd3064caed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.equals(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..cd9066eb8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/read-time-fields-before-datefromfields.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.plaindatetime.prototype.equals +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.plaindatetime.prototype.equals step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.e: + e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + sec-temporal-interprettemporaldatetimefields steps 1–2: + 1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_). + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321, calendar); +const result = datetime.equals({ year: 2021, month: 3, day: 31, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, calendar }); + +assert(result, "time fields are not modified"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/equals/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/equals/year-zero.js new file mode 100644 index 0000000000..d8fe8e7b82 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.equals +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-12-07", + "-000000-12-07T03:24:30", + "-000000-12-07T03:24:30+01:00", + "-000000-12-07T03:24:30+00:00[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/getCalendar/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/branding.js new file mode 100644 index 0000000000..b0a9322aac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getCalendar = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => getCalendar.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/builtin.js new file mode 100644 index 0000000000..593d4112f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.getCalendar), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.getCalendar), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.getCalendar), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.getCalendar.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/length.js new file mode 100644 index 0000000000..bf0fd6d852 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.getCalendar, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/name.js new file mode 100644 index 0000000000..c9ec696b05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.getCalendar, "name", { + value: "getCalendar", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/not-a-constructor.js new file mode 100644 index 0000000000..8e35262749 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.getCalendar(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.getCalendar), false, + "isConstructor(Temporal.PlainDateTime.prototype.getCalendar)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/prop-desc.js new file mode 100644 index 0000000000..cdfecc5979 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getcalendar +description: The "getCalendar" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.getCalendar, + "function", + "`typeof PlainDateTime.prototype.getCalendar` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "getCalendar", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getCalendar/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/getISOFields/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/branding.js new file mode 100644 index 0000000000..a1c1a6d9e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getISOFields = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => getISOFields.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/builtin.js new file mode 100644 index 0000000000..c6dc7cb134 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.getISOFields), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.getISOFields), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.getISOFields), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.getISOFields.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/custom.js new file mode 100644 index 0000000000..dda36e26f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/custom.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.plaindatetime.prototype.getisofields +description: getISOFields does not call into user code. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarThrowEverything(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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.isoHour, 12, "isoHour result"); +assert.sameValue(result.isoMinute, 34, "isoMinute result"); +assert.sameValue(result.isoSecond, 56, "isoSecond result"); +assert.sameValue(result.isoMillisecond, 987, "isoMillisecond result"); +assert.sameValue(result.isoMicrosecond, 654, "isoMicrosecond result"); +assert.sameValue(result.isoNanosecond, 321, "isoNanosecond result"); +assert.sameValue(result.calendar, calendar, "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-names.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-names.js new file mode 100644 index 0000000000..7e0af96024 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-names.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.plaindatetime.prototype.getisofields +description: Correct field names on the object returned from getISOFields +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const result = datetime.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.isoHour, 12, "isoHour result"); +assert.sameValue(result.isoMinute, 34, "isoMinute result"); +assert.sameValue(result.isoSecond, 56, "isoSecond result"); +assert.sameValue(result.isoMillisecond, 987, "isoMillisecond result"); +assert.sameValue(result.isoMicrosecond, 654, "isoMicrosecond result"); +assert.sameValue(result.isoNanosecond, 321, "isoNanosecond result"); +assert.sameValue(result.calendar, "iso8601", "calendar result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-prop-desc.js new file mode 100644 index 0000000000..41e6b2d1e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-prop-desc.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.plaindatetime.prototype.getisofields +description: Properties on the returned object have the correct descriptor +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +const expected = [ + "calendar", + "isoDay", + "isoHour", + "isoMicrosecond", + "isoMillisecond", + "isoMinute", + "isoMonth", + "isoNanosecond", + "isoSecond", + "isoYear", +]; + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const result = datetime.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/PlainDateTime/prototype/getISOFields/field-traversal-order.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-traversal-order.js new file mode 100644 index 0000000000..6d1f676264 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/field-traversal-order.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.plaindatetime.prototype.getisofields +description: Properties added in correct order to object returned from getISOFields +includes: [compareArray.js] +features: [Temporal] +---*/ + +const expected = [ + "calendar", + "isoDay", + "isoHour", + "isoMicrosecond", + "isoMillisecond", + "isoMinute", + "isoMonth", + "isoNanosecond", + "isoSecond", + "isoYear", +]; + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const result = datetime.getISOFields(); + +assert.compareArray(Object.keys(result), expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/length.js new file mode 100644 index 0000000000..3580c33e00 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.getISOFields, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/name.js new file mode 100644 index 0000000000..2f6a0b0691 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.getISOFields, "name", { + value: "getISOFields", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/not-a-constructor.js new file mode 100644 index 0000000000..745bfb8a9a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.getISOFields(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.getISOFields), false, + "isConstructor(Temporal.PlainDateTime.prototype.getISOFields)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/prop-desc.js new file mode 100644 index 0000000000..8addd7338d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: The "getISOFields" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.getISOFields, + "function", + "`typeof PlainDateTime.prototype.getISOFields` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "getISOFields", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/prototype.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/prototype.js new file mode 100644 index 0000000000..9b2fe2de33 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.getisofields +description: Correct prototype on the object returned from getISOFields +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/getISOFields/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/getISOFields/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/hour/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/branding.js new file mode 100644 index 0000000000..7f25864f22 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/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.plaindatetime.prototype.hour +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const hour = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "hour").get; + +assert.sameValue(typeof hour, "function"); + +assert.throws(TypeError, () => hour.call(undefined), "undefined"); +assert.throws(TypeError, () => hour.call(null), "null"); +assert.throws(TypeError, () => hour.call(true), "true"); +assert.throws(TypeError, () => hour.call(""), "empty string"); +assert.throws(TypeError, () => hour.call(Symbol()), "symbol"); +assert.throws(TypeError, () => hour.call(1), "1"); +assert.throws(TypeError, () => hour.call({}), "plain object"); +assert.throws(TypeError, () => hour.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => hour.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/prop-desc.js new file mode 100644 index 0000000000..be1f170bea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/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.plaindatetime.prototype.hour +description: The "hour" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "hour"); +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/PlainDateTime/prototype/hour/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/hour/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/basic.js new file mode 100644 index 0000000000..a6b88825c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.inleapyear +description: Basic test for inLeapYear +features: [Temporal] +---*/ + +assert.sameValue((new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789)).inLeapYear, + true, "leap year"); +assert.sameValue((new Temporal.PlainDateTime(1977, 11, 18, 15, 23, 30, 123, 456, 789)).inLeapYear, + false, "non-leap year"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/branding.js new file mode 100644 index 0000000000..476c99fa05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.inleapyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const inLeapYear = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => inLeapYear.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..122539fc57 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.inLeapYear; + +Object.defineProperty(Temporal.Calendar.prototype, "inLeapYear", inLeapYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/custom.js new file mode 100644 index 0000000000..25daeb1c2b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "inLeapYear arguments"); + return true; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.inLeapYear; +assert.sameValue(result, true, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/prop-desc.js new file mode 100644 index 0000000000..30bdbbeaed --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.inleapyear +description: The "inLeapYear" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/inLeapYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/inLeapYear/validate-calendar-value.js new file mode 100644 index 0000000000..bbcde3216a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, calendar); + assert.sameValue(instance.inLeapYear, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/branding.js new file mode 100644 index 0000000000..ae0dfd4306 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/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.plaindatetime.prototype.microsecond +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const microsecond = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "microsecond").get; + +assert.sameValue(typeof microsecond, "function"); + +assert.throws(TypeError, () => microsecond.call(undefined), "undefined"); +assert.throws(TypeError, () => microsecond.call(null), "null"); +assert.throws(TypeError, () => microsecond.call(true), "true"); +assert.throws(TypeError, () => microsecond.call(""), "empty string"); +assert.throws(TypeError, () => microsecond.call(Symbol()), "symbol"); +assert.throws(TypeError, () => microsecond.call(1), "1"); +assert.throws(TypeError, () => microsecond.call({}), "plain object"); +assert.throws(TypeError, () => microsecond.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => microsecond.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/prop-desc.js new file mode 100644 index 0000000000..f14748090e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/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.plaindatetime.prototype.microsecond +description: The "microsecond" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "microsecond"); +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/PlainDateTime/prototype/microsecond/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/microsecond/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/branding.js new file mode 100644 index 0000000000..806197f618 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/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.plaindatetime.prototype.millisecond +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const millisecond = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "millisecond").get; + +assert.sameValue(typeof millisecond, "function"); + +assert.throws(TypeError, () => millisecond.call(undefined), "undefined"); +assert.throws(TypeError, () => millisecond.call(null), "null"); +assert.throws(TypeError, () => millisecond.call(true), "true"); +assert.throws(TypeError, () => millisecond.call(""), "empty string"); +assert.throws(TypeError, () => millisecond.call(Symbol()), "symbol"); +assert.throws(TypeError, () => millisecond.call(1), "1"); +assert.throws(TypeError, () => millisecond.call({}), "plain object"); +assert.throws(TypeError, () => millisecond.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => millisecond.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/prop-desc.js new file mode 100644 index 0000000000..67667b89f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/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.plaindatetime.prototype.millisecond +description: The "millisecond" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "millisecond"); +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/PlainDateTime/prototype/millisecond/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/millisecond/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/branding.js new file mode 100644 index 0000000000..b8c7df0cbc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/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.plaindatetime.prototype.minute +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const minute = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "minute").get; + +assert.sameValue(typeof minute, "function"); + +assert.throws(TypeError, () => minute.call(undefined), "undefined"); +assert.throws(TypeError, () => minute.call(null), "null"); +assert.throws(TypeError, () => minute.call(true), "true"); +assert.throws(TypeError, () => minute.call(""), "empty string"); +assert.throws(TypeError, () => minute.call(Symbol()), "symbol"); +assert.throws(TypeError, () => minute.call(1), "1"); +assert.throws(TypeError, () => minute.call({}), "plain object"); +assert.throws(TypeError, () => minute.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => minute.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/prop-desc.js new file mode 100644 index 0000000000..b8294ac693 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/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.plaindatetime.prototype.minute +description: The "minute" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "minute"); +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/PlainDateTime/prototype/minute/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/minute/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/branding.js new file mode 100644 index 0000000000..0b3cfafaac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.month +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const month = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => month.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..297016272f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.month; + +Object.defineProperty(Temporal.Calendar.prototype, "month", monthOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/custom.js new file mode 100644 index 0000000000..2bc1a17f12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "month arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.month; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/prop-desc.js new file mode 100644 index 0000000000..513395b28a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.month +description: The "month" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/month/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/month/validate-calendar-value.js new file mode 100644 index 0000000000..d53f50541d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/monthCode/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/branding.js new file mode 100644 index 0000000000..a327685c07 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.monthcode +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthCode = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => monthCode.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..eec179a36a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.monthCode; + +Object.defineProperty(Temporal.Calendar.prototype, "monthCode", monthCodeOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/custom.js new file mode 100644 index 0000000000..27ebb31985 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "monthCode arguments"); + return "M01"; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.monthCode; +assert.sameValue(result, "M01", "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/prop-desc.js new file mode 100644 index 0000000000..0f8fb871ce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.monthcode +description: The "monthCode" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/monthCode/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthCode/validate-calendar-value.js new file mode 100644 index 0000000000..1f17391289 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/monthsInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/basic.js new file mode 100644 index 0000000000..a1e7d322ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/basic.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-get-temporal.plaindatetime.prototype.monthsinyear +description: Checking months in year for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +assert.sameValue(datetime.monthsInYear, 12, "check months in year information"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/branding.js new file mode 100644 index 0000000000..24380ac91f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.monthsinyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const monthsInYear = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => monthsInYear.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..b9a114f28c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.monthsInYear; + +Object.defineProperty(Temporal.Calendar.prototype, "monthsInYear", monthsInYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/custom.js new file mode 100644 index 0000000000..c0af9d53c8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "monthsInYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.monthsInYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/prop-desc.js new file mode 100644 index 0000000000..17d83e9ddd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.monthsinyear +description: The "monthsInYear" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/monthsInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/monthsInYear/validate-calendar-value.js new file mode 100644 index 0000000000..0bdce32ca5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/nanosecond/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/branding.js new file mode 100644 index 0000000000..45a90d8547 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/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.plaindatetime.prototype.nanosecond +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const nanosecond = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "nanosecond").get; + +assert.sameValue(typeof nanosecond, "function"); + +assert.throws(TypeError, () => nanosecond.call(undefined), "undefined"); +assert.throws(TypeError, () => nanosecond.call(null), "null"); +assert.throws(TypeError, () => nanosecond.call(true), "true"); +assert.throws(TypeError, () => nanosecond.call(""), "empty string"); +assert.throws(TypeError, () => nanosecond.call(Symbol()), "symbol"); +assert.throws(TypeError, () => nanosecond.call(1), "1"); +assert.throws(TypeError, () => nanosecond.call({}), "plain object"); +assert.throws(TypeError, () => nanosecond.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => nanosecond.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/prop-desc.js new file mode 100644 index 0000000000..89b1843e50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/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.plaindatetime.prototype.nanosecond +description: The "nanosecond" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "nanosecond"); +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/PlainDateTime/prototype/nanosecond/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/nanosecond/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/prop-desc.js new file mode 100644 index 0000000000..c95a815a3c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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-plaindatetime-prototype +description: The "prototype" property of Temporal.PlainDateTime +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue(typeof Temporal.PlainDateTime.prototype, "object"); +assert.notSameValue(Temporal.PlainDateTime.prototype, null); + +verifyProperty(Temporal.PlainDateTime, "prototype", { + writable: false, + enumerable: false, + configurable: false, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/balance.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/balance.js new file mode 100644 index 0000000000..550f5ccd88 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/balance.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.plaindatetime.prototype.round +description: Rounding balances to the next smallest unit +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 23, 59, 59, 999, 999, 999); + +["day", "hour", "minute", "second", "millisecond", "microsecond"].forEach((smallestUnit) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit }), + 1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0, + `balances to next ${smallestUnit}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/branding.js new file mode 100644 index 0000000000..e8f620dbc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const round = Temporal.PlainDateTime.prototype.round; + +assert.sameValue(typeof round, "function"); + +const args = ['hour']; + +assert.throws(TypeError, () => round.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => round.apply(null, args), "null"); +assert.throws(TypeError, () => round.apply(true, args), "true"); +assert.throws(TypeError, () => round.apply("", args), "empty string"); +assert.throws(TypeError, () => round.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => round.apply(1, args), "1"); +assert.throws(TypeError, () => round.apply({}, args), "plain object"); +assert.throws(TypeError, () => round.apply(Temporal.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => round.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/builtin.js new file mode 100644 index 0000000000..f906a20fa6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: > + Tests that Temporal.PlainDateTime.prototype.round + 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.PlainDateTime.prototype.round), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.round), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.round), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.round.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/length.js new file mode 100644 index 0000000000..2f32b93ea5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: Temporal.PlainDateTime.prototype.round.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.PlainDateTime.prototype.round, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/limits.js new file mode 100644 index 0000000000..7a12038973 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/limits.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.plaindatetime.prototype.round +description: Checking limits of representable PlainDateTime +features: [Temporal] +---*/ + +const min = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1); +const max = new Temporal.PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999); + +["day", "hour", "minute", "second", "millisecond", "microsecond"].forEach((smallestUnit) => { + assert.throws( + RangeError, + () => min.round({ smallestUnit, roundingMode: "floor" }), + `rounding beyond limit (unit = ${smallestUnit}, rounding mode = floor)` + ); + assert.throws( + RangeError, + () => max.round({ smallestUnit, roundingMode: "ceil" }), + `rounding beyond limit (unit = ${smallestUnit}, rounding mode = ceil)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/name.js new file mode 100644 index 0000000000..bd1fc4cb17 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: Temporal.PlainDateTime.prototype.round.name is "round". +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.PlainDateTime.prototype.round, "name", { + value: "round", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/not-a-constructor.js new file mode 100644 index 0000000000..664de7a906 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: > + Temporal.PlainDateTime.prototype.round 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.PlainDateTime.prototype.round(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.round), false, + "isConstructor(Temporal.PlainDateTime.prototype.round)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.js new file mode 100644 index 0000000000..b30b8481a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/options-wrong-type.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.plaindatetime.prototype.round +description: TypeError thrown when options argument is missing or a non-string primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + undefined, + null, + true, + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +assert.throws(TypeError, () => instance.round(), "TypeError on missing options argument"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.round(value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/prop-desc.js new file mode 100644 index 0000000000..f4dee3b7c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: The "round" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.round, + "function", + "`typeof PlainDateTime.prototype.round` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "round", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.js new file mode 100644 index 0000000000..2193d200b2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/rounding-direction.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.plaindatetime.prototype.round +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(-99, 12, 15, 12, 0, 0, 500); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "floor" }), + -99, 12, "M12", 15, 12, 0, 0, 0, 0, 0, + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode floor)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "trunc" }), + -99, 12, "M12", 15, 12, 0, 0, 0, 0, 0, + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "ceil" }), + -99, 12, "M12", 15, 12, 0, 1, 0, 0, 0, + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit: "second", roundingMode: "halfExpand" }), + -99, 12, "M12", 15, 12, 0, 1, 0, 0, 0, + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.js new file mode 100644 index 0000000000..51bdf65d7f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-divides.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.plaindatetime.prototype.round +description: Rounding increment should properly divide the relevant time unit +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +[1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit: "hour", roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid hour increments divide into 24 (rounding increment = ${roundingIncrement})`); +}); + +["minute", "second"].forEach((smallestUnit) => { + [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit, roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid ${smallestUnit} increments divide into 60 (rounding increment = ${roundingIncrement})` + ); + }); +}); + +["millisecond", "microsecond", "nanosecond"].forEach((smallestUnit) => { + [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { + assert.sameValue( + dt.round({ smallestUnit, roundingIncrement }) instanceof Temporal.PlainDateTime, + true, + `valid ${smallestUnit} increments divide into 1000 (rounding increment = ${roundingIncrement})`); + }); +}); + +const nextIncrements = { + "hour": 24, + "minute": 60, + "second": 60, + "millisecond": 1000, + "microsecond": 1000, + "nanosecond": 1000 +}; + +Object.entries(nextIncrements).forEach(([unit, next]) => { + assert.throws( + RangeError, + () => dt.round({ smallestUnit: unit, roundingIncrement: next }), + `throws on increments that are equal to the next highest (unit = ${unit}, increment = ${next})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.js new file mode 100644 index 0000000000..df4a40dfe6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-does-not-divide.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.plaindatetime.prototype.round +description: Throw exception if the rounding unit does not properly divide the relevant time unit +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); +const units = ["day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]; +units.forEach((unit) => { + assert.throws( + RangeError, + () => dt.round({ smallestUnit: unit, roundingIncrement: 29 }), + `throws on increments that do not divide evenly into the next highest (unit = ${unit})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-nan.js new file mode 100644 index 0000000000..c87e6f24c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-nan.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.plaindatetime.prototype.round +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-totemporaldatetimeroundingincrement step 5: + 5. Return ? ToTemporalRoundingIncrement(_normalizedOptions_, _maximum_, *false*). + sec-temporal.plaindatetime.prototype.round step 8: + 8. Let _roundingIncrement_ be ? ToTemporalDateTimeRoundingIncrement(_options_, _smallestUnit_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +assert.throws(RangeError, () => datetime.round({ smallestUnit: 'second', roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-non-integer.js new file mode 100644 index 0000000000..646f4e2143 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-non-integer.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.plaindatetime.prototype.round +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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +const result = datetime.round({ smallestUnit: "nanosecond", roundingIncrement: 2.5, roundingMode: "expand" }); +TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 0, 0, 6, "roundingIncrement 2.5 truncates to 2"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.js new file mode 100644 index 0000000000..7d48e74944 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-one-day.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.plaindatetime.prototype.round +description: One day is a valid rounding increment +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "day", roundingIncrement: 1 }), + 1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0, + "1 day is a valid increment" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..4c3be90a69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-out-of-range.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.plaindatetime.prototype.round +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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: -Infinity })); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: -1 })); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: 0 })); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: 0.9 })); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: 1e9 + 1 })); +assert.throws(RangeError, () => datetime.round({ smallestUnit: "nanoseconds", roundingIncrement: Infinity })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-undefined.js new file mode 100644 index 0000000000..d5bbcce128 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-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.plaindatetime.prototype.round +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-totemporaldatetimeroundingincrement step 5: + 5. Return ? ToTemporalRoundingIncrement(_normalizedOptions_, _maximum_, *false*). + sec-temporal.plaindatetime.prototype.round step 8: + 8. Let _roundingIncrement_ be ? ToTemporalDateTimeRoundingIncrement(_options_, _smallestUnit_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const explicit = datetime.round({ smallestUnit: 'second', roundingIncrement: undefined }); +TemporalHelpers.assertPlainDateTime(explicit, 2000, 5, "M05", 2, 12, 34, 57, 0, 0, 0, "default roundingIncrement is 1"); + +const implicit = datetime.round({ smallestUnit: 'second' }); +TemporalHelpers.assertPlainDateTime(implicit, 2000, 5, "M05", 2, 12, 34, 57, 0, 0, 0, "default roundingIncrement is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..05c5d22697 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingincrement-wrong-type.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.plaintime.prototype.round +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-totemporaldatetimeroundingincrement step 5: + 5. Return ? ToTemporalRoundingIncrement(_normalizedOptions_, _maximum_, *false*). + sec-temporal.plaindatetime.prototype.round step 8: + 8. Let _roundingIncrement_ be ? ToTemporalDateTimeRoundingIncrement(_options_, _smallestUnit_). +includes: [temporalHelpers.js, compareArray.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => datetime.round({ smallestUnit: 'second', roundingIncrement }), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 57, 0, 0, 0, descr), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.js new file mode 100644 index 0000000000..085b8bac3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-basic.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.plaindatetime.prototype.round +description: Basic checks for rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "hour", roundingIncrement: 4 }), + 1976, 11, "M11", 18, 16, 0, 0, 0, 0, 0, + "rounds to an increment of hours" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "minute", roundingIncrement: 15 }), + 1976, 11, "M11", 18, 14, 30, 0, 0, 0, 0, + "rounds to an increment of minutes" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "second", roundingIncrement: 30 }), + 1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0, + "rounds to an increment of seconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "millisecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 120, 0, 0, + "rounds to an increment of milliseconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "microsecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 123, 460, 0, + "rounds to an increment of microseconds" +); + +TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: "nanosecond", roundingIncrement: 10 }), + 1976, 11, "M11", 18, 14, 23, 30, 123, 456, 790, + "rounds to an increment of nanoseconds" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil.js new file mode 100644 index 0000000000..6363a0b9f0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-ceil.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 15]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 31]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 988]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "ceil"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-expand.js new file mode 100644 index 0000000000..00b8ab4742 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-expand.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 15]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 31]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 988]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "expand"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor.js new file mode 100644 index 0000000000..1a70fe0c2c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-floor.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 18]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 23]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 123]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "floor"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfCeil.js new file mode 100644 index 0000000000..57a84b3cd6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfCeil.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 988]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "halfCeil"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfEven.js new file mode 100644 index 0000000000..b65c21d152 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfEven.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 988]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "halfEven"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfExpand.js new file mode 100644 index 0000000000..8e5c31cc24 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfExpand.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 988]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "halfExpand"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfFloor.js new file mode 100644 index 0000000000..9eb15ee2a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfFloor.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "halfFloor"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..7a6534d351 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfTrunc.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 19]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 24]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 124]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "halfTrunc"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.js new file mode 100644 index 0000000000..5a66171d04 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfexpand-is-default.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.plaindatetime.prototype.round +description: Half-expand is the default rounding mode +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +const units = { + "day": [1976, 11, "M11", 19, 0, 0, 0, 0, 0, 0], + "hour": [1976, 11, "M11", 18, 14, 0, 0, 0, 0, 0], + "minute": [1976, 11, "M11", 18, 14, 24, 0, 0, 0, 0], + "second": [1976, 11, "M11", 18, 14, 23, 30, 0, 0, 0], + "millisecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 0, 0], + "microsecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 457, 0], + "nanosecond": [1976, 11, "M11", 18, 14, 23, 30, 123, 456, 789] +}; + +const expected = [1976, 11, "M11", 18, 0, 0, 0, 0, 0, 0]; + +Object.entries(units).forEach(([unit, expected]) => { + TemporalHelpers.assertPlainDateTime( + dt.round({ smallestUnit: unit }), + ...expected, + `halfExpand is the default (smallest unit = ${unit}, rounding mode absent)` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-invalid-string.js new file mode 100644 index 0000000000..8bb99a0d7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-invalid-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.round +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +for (const roundingMode of ["other string", "cile", "CEIL", "ce\u0131l", "auto", "halfexpand", "floor\0"]) { + assert.throws(RangeError, () => datetime.round({ smallestUnit: "microsecond", roundingMode })); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc.js new file mode 100644 index 0000000000..51634108db --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-trunc.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.plaindatetime.prototype.round +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 987, 500); + +const expected = [ + ["day", [1976, 11, 'M11', 18]], + ["hour", [1976, 11, 'M11', 18, 14]], + ["minute", [1976, 11, 'M11', 18, 14, 23]], + ["second", [1976, 11, 'M11', 18, 14, 23, 30]], + ["millisecond", [1976, 11, 'M11', 18, 14, 23, 30, 123]], + ["microsecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987]], + ["nanosecond", [1976, 11, 'M11', 18, 14, 23, 30, 123, 987, 500]], +]; + +const roundingMode = "trunc"; + +expected.forEach(([smallestUnit, expected]) => { + const [y, mon, mc, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected; + TemporalHelpers.assertPlainDateTime( + instance.round({ smallestUnit, roundingMode }), + y, mon, mc, d, h, min, s, ms, µs, ns, + `rounds to ${smallestUnit} (roundingMode = ${roundingMode})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-undefined.js new file mode 100644 index 0000000000..852164e980 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-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.plaindatetime.prototype.round +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const explicit1 = datetime.round({ smallestUnit: "microsecond", roundingMode: undefined }); +TemporalHelpers.assertPlainDateTime(explicit1, 2000, 5, "M05", 2, 12, 34, 56, 123, 988, 0, "default roundingMode is halfExpand"); +const implicit1 = datetime.round({ smallestUnit: "microsecond" }); +TemporalHelpers.assertPlainDateTime(implicit1, 2000, 5, "M05", 2, 12, 34, 56, 123, 988, 0, "default roundingMode is halfExpand"); + +const explicit2 = datetime.round({ smallestUnit: "millisecond", roundingMode: undefined }); +TemporalHelpers.assertPlainDateTime(explicit2, 2000, 5, "M05", 2, 12, 34, 56, 124, 0, 0, "default roundingMode is halfExpand"); +const implicit2 = datetime.round({ smallestUnit: "millisecond" }); +TemporalHelpers.assertPlainDateTime(implicit2, 2000, 5, "M05", 2, 12, 34, 56, 124, 0, 0, "default roundingMode is halfExpand"); + +const explicit3 = datetime.round({ smallestUnit: "second", roundingMode: undefined }); +TemporalHelpers.assertPlainDateTime(explicit3, 2000, 5, "M05", 2, 12, 34, 56, 0, 0, 0, "default roundingMode is halfExpand"); +const implicit3 = datetime.round({ smallestUnit: "second" }); +TemporalHelpers.assertPlainDateTime(implicit3, 2000, 5, "M05", 2, 12, 34, 56, 0, 0, 0, "default roundingMode is halfExpand"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-wrong-type.js new file mode 100644 index 0000000000..58da6f97c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-wrong-type.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.plaindatetime.prototype.round +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "halfExpand", + (roundingMode) => datetime.round({ smallestUnit: "microsecond", roundingMode }), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 123, 988, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundto-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundto-invalid-string.js new file mode 100644 index 0000000000..e466c5c37a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/roundto-invalid-string.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.plaindatetime.prototype.round +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.round(smallestUnit), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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/PlainDateTime/prototype/round/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.js new file mode 100644 index 0000000000..fe08dcf32f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-invalid-string.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.plaindatetime.prototype.round +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.round({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..5883d38140 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-plurals-accepted.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.plaindatetime.prototype.round +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 789, 999, 999); +const validUnits = [ + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => datetime.round({ smallestUnit }), validUnits); +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => datetime.round(smallestUnit), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-string-shorthand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-string-shorthand.js new file mode 100644 index 0000000000..98e903dc48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-string-shorthand.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.plaindatetime.prototype.round +description: String as first argument is equivalent to options bag with smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 789, 999, 999); +const validUnits = [ + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +validUnits.forEach((smallestUnit) => { + const full = instance.round({ smallestUnit }); + const shorthand = instance.round(smallestUnit); + TemporalHelpers.assertPlainDateTimesEqual(shorthand, full, `"${smallestUnit}" as first argument to round is equivalent to options bag`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-wrong-type.js new file mode 100644 index 0000000000..58438c8163 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/smallestunit-wrong-type.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.plaindatetime.prototype.round +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "microsecond", + (smallestUnit) => datetime.round({ smallestUnit }), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 123, 988, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/subclassing-ignored.js new file mode 100644 index 0000000000..1a4fad9078 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/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.plaindatetime.prototype.round +description: Objects of a subclass are never created as return values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "round", + [{ smallestUnit: 'second' }], + (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 57, 0, 0, 0), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.js new file mode 100644 index 0000000000..5a78bfc8e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object-insufficient-data.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.plaindatetime.prototype.round +description: Throw if smallest unit is missing from argument +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + RangeError, + () => dt.round({ roundingIncrement: 1, roundingMode: "ceil" }), + "throws without required smallestUnit parameter" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.js new file mode 100644 index 0000000000..3087ab282a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-argument-object.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.plaindatetime.prototype.round +description: Throw if argument is an empty plain object +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + RangeError, + () => dt.round({}), + "throws on empty object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.js new file mode 100644 index 0000000000..7d3b5cc82b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-no-argument.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.plaindatetime.prototype.round +description: Throw if no arguments at all are given +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => dt.round(), + "throws without any parameters" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-undefined.js new file mode 100644 index 0000000000..3e1e32fc93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/round/throws-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.plaindatetime.prototype.round +description: Throw if sole argument is undefined +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 14, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => dt.round(undefined), + "throws without undefined as sole parameter" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/branding.js new file mode 100644 index 0000000000..8b168faf11 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/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.plaindatetime.prototype.second +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const second = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "second").get; + +assert.sameValue(typeof second, "function"); + +assert.throws(TypeError, () => second.call(undefined), "undefined"); +assert.throws(TypeError, () => second.call(null), "null"); +assert.throws(TypeError, () => second.call(true), "true"); +assert.throws(TypeError, () => second.call(""), "empty string"); +assert.throws(TypeError, () => second.call(Symbol()), "symbol"); +assert.throws(TypeError, () => second.call(1), "1"); +assert.throws(TypeError, () => second.call({}), "plain object"); +assert.throws(TypeError, () => second.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => second.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/prop-desc.js new file mode 100644 index 0000000000..ebed5d7c63 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/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.plaindatetime.prototype.second +description: The "second" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.prototype, "second"); +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/PlainDateTime/prototype/second/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/second/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..5ef369ced3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const arg = { year: 2000, month: 5, day: 2, hour: 21, minute: 43, second: 5, calendar: "iso8601" }; +instance.since(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-number.js new file mode 100644 index 0000000000..ba9ca1e11a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: A number cannot be used in place of a Temporal.PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.since(arg), + `A number (${arg}) is not a valid ISO string for PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-object.js new file mode 100644 index 0000000000..57b3654f02 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-object.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.plaindatetime.prototype.since +description: Plain objects are accepted as an argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertDuration( + dt.since({ year: 2019, month: 10, day: 29, hour: 10 }), + 0, 0, 0, -15684, -18, -36, -29, -876, -543, -211, + "casts argument (plain object)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-plaindate.js new file mode 100644 index 0000000000..07fc4c0423 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-plaindate.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.plaindatetime.prototype.since +description: Fast path for converting Temporal.PlainDate to Temporal.PlainDateTime by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.b: + b. If _item_ has an [[InitializedTemporalDate]] internal slot, then + i. Return ? CreateTemporalDateTime(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], 0, 0, 0, 0, 0, 0, _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalPlainDateTimeFastPath((date, calendar) => { + const datetime = new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 987, 654, 321, calendar); + const result = datetime.since(date); + assert.sameValue(result.total({ unit: "nanoseconds" }), 987654321, "PlainDate is converted to midnight"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..d35b163b19 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/since/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..1a344939c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(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/PlainDateTime/prototype/since/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..9c7f65ec05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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/PlainDateTime/prototype/since/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..a4a4e10cd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/since/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..d3a8e5aba7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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/PlainDateTime/prototype/since/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..6cd66acaf2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/since/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..2fa40a1aee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-calendar-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[u-ca=iso8601]", "without time zone"], + ["1976-11-18T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["1976-11-18T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["1976-11-18T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["1976-11-18T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/since/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..b0b311f210 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/since/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..017213c52c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +const validStrings = [ + "1976-11-18T15:23+00:00", + "1976-11-18T15:23+00:00[UTC]", + "1976-11-18T15:23+00:00[!UTC]", + "1976-11-18T15:23-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 PlainDateTime` + ); +} + +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 PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..6f358f3325 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/since/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..c99a4af9c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/since/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-time-separators.js new file mode 100644 index 0000000000..0f15f572a4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23", "uppercase T"], + ["1976-11-18t15:23", "lowercase T"], + ["1976-11-18 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/since/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..81a90f173c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-time-zone-annotation.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[Asia/Kolkata]", "named, with no offset"], + ["1976-11-18T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["1976-11-18T15:23[+00:00]", "numeric, with no offset"], + ["1976-11-18T15:23[!-02:30]", "numeric, with ! and no offset"], + ["1976-11-18T15:23+00:00[UTC]", "named, with offset"], + ["1976-11-18T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1976-11-18T15:23+00:00[+01:00]", "numeric, with offset"], + ["1976-11-18T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/since/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..3960259916 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-unknown-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[foo=bar]", "alone"], + ["1976-11-18T15:23[UTC][foo=bar]", "with time zone"], + ["1976-11-18T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["1976-11-18T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1976-11-18T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/since/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..cc0b2f2449 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: RangeError thrown if a string with UTC designator is used as a PlainDateTime +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.since(arg), + "String with UTC designator should not be valid as a PlainDateTime" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-string.js new file mode 100644 index 0000000000..f1d3237a1e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-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.plaindatetime.prototype.since +description: Date-like string arguments are acceptable +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertDuration( + dt.since("2019-10-29T10:46:38.271986102"), + 0, 0, 0, -15684, -19, -23, -8, -148, -529, -313, + "casts argument (string)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-wrong-type.js new file mode 100644 index 0000000000..fb55c45f60 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDateTime +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.PlainDateTime, "Temporal.PlainDateTime, object"], + [Temporal.PlainDateTime.prototype, "Temporal.PlainDateTime.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/PlainDateTime/prototype/since/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..803747b39b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-balance-negative-time-units.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: 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-totemporaldatetime step 3.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + ... + ii. 1. Return ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). + sec-temporal.plaindatetime.prototype.since step 3: + 3. Set _other_ ? ToTemporalDateTime(_other_). +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 diff = new Temporal.PlainDateTime(1970, 1, 1).since(datetime); + +TemporalHelpers.assertDuration(diff, 0, 0, 0, 0, -1, -1, -1, -1, 0, -999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..a128e5820b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/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.plaindatetime.prototype.since +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.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +const result = instance.since(datetime); +TemporalHelpers.assertDuration(result, 0, 0, 0, 11239, 22, 40, 10, 987, 654, 320); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..76738f0272 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.since(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..1fd51aa6b3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => plain.since(zoned), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..0838e28752 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.since(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..c9fcd949d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => plain.since(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-duration.js new file mode 100644 index 0000000000..901ede1927 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-duration.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.plaindatetime.prototype.since +description: Negative durations are balanced correctly by the modulo operation in NanosecondsToDays +info: | + sec-temporal-nanosecondstodays step 6: + 6. If Type(_relativeTo_) is not Object or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot, then + a. Return the new Record { ..., [[Nanoseconds]]: abs(_nanoseconds_) modulo _dayLengthNs_ × _sign_, ... }. + sec-temporal-balanceduration step 4: + 4. If _largestUnit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*, then + a. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _relativeTo_). + sec-temporal-differenceisodatetime steps 7 and 13: + 7. If _timeSign_ is -_dateSign_, then + ... + b. Set _timeDifference_ to ? BalanceDuration(-_timeSign_, _timeDifference_.[[Hours]], _timeDifference_.[[Minutes]], _timeDifference_.[[Seconds]], _timeDifference_.[[Milliseconds]], _timeDifference_.[[Microseconds]], _timeDifference_.[[Nanoseconds]], _largestUnit_). + ... + 16. Return ? BalanceDuration(_dateDifference_.[[Years]], _dateDifference_.[[Months]], _dateDifference_.[[Weeks]], _dateDifference_.[[Days]], _timeDifference_.[[Hours]], _timeDifference_.[[Minutes]], _timeDifference_.[[Seconds]], _timeDifference_.[[Milliseconds]], _timeDifference_.[[Microseconds]], _timeDifference_.[[Nanoseconds]], _largestUnit_). + sec-temporal.plaindatetime.prototype.since step 14: + 14. Let _diff_ be ? DifferenceISODateTime(_other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier1 = new Temporal.PlainDateTime(2000, 5, 2, 9); +const later1 = new Temporal.PlainDateTime(2000, 5, 5, 10); +const result1 = later1.since(earlier1, { largestUnit: 'day' }); +TemporalHelpers.assertDuration(result1, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, "date sign == time sign"); + +const earlier2 = new Temporal.PlainDateTime(2000, 5, 2, 10); +const later2 = new Temporal.PlainDateTime(2000, 5, 5, 9); +const result2 = later2.since(earlier2, { largestUnit: 'day' }); +TemporalHelpers.assertDuration(result2, 0, 0, 0, 2, 23, 0, 0, 0, 0, 0, "date sign != time sign"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-time-units.js new file mode 100644 index 0000000000..d4f1df6ea2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-time-units.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.plaindatetime.prototype.since +description: Negative time fields are balanced upwards +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-differencetime step 8: + 8. Let _bt_ be ? BalanceTime(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). + sec-temporal-differenceisodatetime step 2: + 2. Let _timeDifference_ be ? DifferenceTime(_h1_, _min1_, _s1_, _ms1_, _mus1_, _ns1_, _h2_, _min2_, _s2_, _ms2_, _mus2_, _ns2_). + sec-temporal.plaindatetime.prototype.since step 14: + 14. Let _diff_ be ? DifferenceISODateTime(_other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1996, 5, 2, 1, 1, 1, 1, 1, 1); + +const result1 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertDuration(result1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 999, "nanoseconds balance"); + +const result2 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 0, 2)); +TemporalHelpers.assertDuration(result2, 0, 0, 0, 0, 1, 1, 1, 0, 999, 1, "microseconds balance"); + +const result3 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 2)); +TemporalHelpers.assertDuration(result3, 0, 0, 0, 0, 1, 1, 0, 999, 1, 1, "milliseconds balance"); + +const result4 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 2)); +TemporalHelpers.assertDuration(result4, 0, 0, 0, 0, 1, 0, 59, 1, 1, 1, "seconds balance"); + +const result5 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 0, 2)); +TemporalHelpers.assertDuration(result5, 0, 0, 0, 0, 0, 59, 1, 1, 1, 1, "minutes balance"); + +// This one is different because hours are later balanced again in BalanceDuration +const result6 = datetime.since(new Temporal.PlainDateTime(1996, 5, 2, 2)); +TemporalHelpers.assertDuration(result6, 0, 0, 0, 0, 0, -58, -58, -998, -998, -999, "hours balance"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/branding.js new file mode 100644 index 0000000000..e5d37d2d5b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const since = Temporal.PlainDateTime.prototype.since; + +assert.sameValue(typeof since, "function"); + +const args = [new Temporal.PlainDateTime(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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => since.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..8645aec4f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.since(new Temporal.PlainDateTime(1999, 4, 1)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/builtin.js new file mode 100644 index 0000000000..b559811c5a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.since), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.since), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.since), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.since.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..e50a5121fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, calendar); +instance.since(new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 0, 0, 0, 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/PlainDateTime/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..c7e9451467 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/since/calendar-dateuntil-called-with-copy-of-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-copy-of-options.js new file mode 100644 index 0000000000..25a93951fb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-copy-of-options.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: The dateUntil() method on the calendar is called with a copy of the options bag +features: [Temporal] +---*/ + +const originalOptions = { + largestUnit: "year", + shouldBeCopied: {}, +}; +let called = false; + +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + + dateUntil(d1, d2, options) { + called = true; + assert.notSameValue(options, originalOptions, "options bag should be a copy"); + assert.sameValue(options.shouldBeCopied, originalOptions.shouldBeCopied, "options bag should be a shallow copy"); + return new Temporal.Duration(); + } +} +const calendar = new Calendar(); +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); +earlier.since(later, originalOptions); +assert(called, "calendar.dateUntil must be called"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..58d5037862 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const argument = new Temporal.PlainDateTime(2022, 6, 14, 18, 21, 36, 660, 690, 387, 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/PlainDateTime/prototype/since/calendar-dateuntil-called-with-plaindate-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-plaindate-calendar.js new file mode 100644 index 0000000000..cdb2988218 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-plaindate-calendar.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.plaindatetime.prototype.since +description: calendar.dateUntil() is passed PlainDate objects with the receiver's calendar +info: | + DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit [ , options ] ) + + 8. Let _date1_ be ? CreateTemporalDate(_balanceResult_.[[Year]], _balanceResult_.[[Month]], _balanceResult_.[[Day]], _calendar_). + 9. Let _date2_ be ? CreateTemporalDate(_y2_, _mon2_, _d2_, _calendar_). + 12. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _date1_, _date2_, _untilOptions_). +features: [Temporal] +---*/ + +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + + dateUntil(d1, d2) { + assert.sameValue(d1.getCalendar(), this, "d1.calendar"); + assert.sameValue(d2.getCalendar(), this, "d2.calendar"); + return new Temporal.Duration(); + } +} +const calendar = new Calendar(); +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); +const result = earlier.since(later); +assert(result instanceof Temporal.Duration, "result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..fbcd184fc1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js @@ -0,0 +1,39 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plaindatetime.prototype.since step 14: + 14. Let _diff_ be ? DifferenceISODateTime(_other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). + sec-temporal-differenceisodatetime steps 9–11: + 9. Let _dateLargestUnit_ be ! LargerOfTwoTemporalUnits(*"day"*, _largestUnit_). + 10. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _dateLargestUnit_). + 11. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _date1_, _date2_, _untilOptions_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); + const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); + later.since(earlier, { largestUnit }); + }, + { + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-fields-iterable.js new file mode 100644 index 0000000000..36e4e4ee78 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +datetime.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/PlainDateTime/prototype/since/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/calendar-temporal-object.js new file mode 100644 index 0000000000..6a264c5b07 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime 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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, temporalObject); + datetime.since({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..051d7f7fce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/different-calendars-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/different-calendars-throws.js new file mode 100644 index 0000000000..3ea7e14b34 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/different-calendars-throws.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.plaindatetime.prototype.since +description: Fail if the argument is a PlainDateTime with a different calendar +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0); +const dt2 = new Temporal.PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "custom", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +assert.throws( + RangeError, + () => dt1.since(dt2), + "different calendars not allowed" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/duplicate-calendar-fields.js new file mode 100644 index 0000000000..5a714170e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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'], ['hour'], ['microsecond'], ['millisecond'], ['minute'], ['month'], ['monthCode'], ['nanosecond'], ['second'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + + assert.throws(RangeError, () => instance.since(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..1845f4ccc2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15); +const base = { year: 2000, month: 5, day: 2, hour: 15, minute: 30, second: 45, millisecond: 987, microsecond: 654, nanosecond: 321 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].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/PlainDateTime/prototype/since/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-invalid-string.js new file mode 100644 index 0000000000..e67796f959 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-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.plaindatetime.prototype.since +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..df1ef728cc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-plurals-accepted.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.plaindatetime.prototype.since +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 12, 13, 35, 57, 988, 655, 322); +const validUnits = [ + "year", + "month", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => later.since(earlier, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..4b902d0f69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +const units = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; +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/PlainDateTime/prototype/since/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-undefined.js new file mode 100644 index 0000000000..780b25118f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); + +const explicit = later.since(earlier, { largestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 1, 1, 1, 987, 654, 321, "default largestUnit is day"); +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 1, 1, 1, 987, 654, 321, "default largestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit-wrong-type.js new file mode 100644 index 0000000000..12f194cd64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "year", + (largestUnit) => later.since(earlier, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 1, 1, 1, 1, 987, 654, 321, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/largestunit.js new file mode 100644 index 0000000000..852a7b8068 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Specify behavior of PlainDateTime.since when largest specified unit is years or months. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ +const lastFeb20 = new Temporal.PlainDateTime(2020, 2, 20, 5, 45, 20); +const lastFeb21 = new Temporal.PlainDateTime(2021, 2, 21, 17, 18, 57); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20), 0, 0, 0, 367, 11, 33, 37, 0, 0, 0, 'does not include higher units than necessary (largest unit unspecified)'); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: 'months' }), 0, 12, 0, 1, 11, 33, 37, 0, 0, 0, 'does not include higher units than necessary (largest unit is months)'); +TemporalHelpers.assertDuration(lastFeb21.since(lastFeb20, { largestUnit: 'years' }), 1, 0, 0, 1, 11, 33, 37, 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/PlainDateTime/prototype/since/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/leap-second.js new file mode 100644 index 0000000000..62e2963d22 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/leap-second.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Leap second is a valid ISO string for PlainDateTime +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2016, 12, 31, 23, 59, 59); + +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 PlainDateTime" +); + +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 PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/length.js new file mode 100644 index 0000000000..944b5458a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.since, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/name.js new file mode 100644 index 0000000000..eb45ee1e00 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.since, "name", { + value: "since", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/no-unnecessary-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/no-unnecessary-units.js new file mode 100644 index 0000000000..62ec2d003e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/no-unnecessary-units.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.plaindatetime.prototype.since +description: Do not return Durations with unnecessary units +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb2 = new Temporal.PlainDateTime(2020, 2, 2, 0, 0); +const feb28 = new Temporal.PlainDateTime(2021, 2, 28, 0, 0); + +TemporalHelpers.assertDuration( + feb28.since(feb2), + 0, 0, 0, 392, 0, 0, 0, 0, 0, 0, + "does not include higher units than necessary (no largest unit)" +); + +TemporalHelpers.assertDuration( + feb28.since(feb2, { largestUnit: "months" }), + 0, 12, 0, 26, 0, 0, 0, 0, 0, 0, + "does not include higher units than necessary (largest unit = months)" +); + +TemporalHelpers.assertDuration( + feb28.since(feb2, { largestUnit: "years" }), + 1, 0, 0, 26, 0, 0, 0, 0, 0, 0, + "does not include higher units than necessary (largest unit = years)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/not-a-constructor.js new file mode 100644 index 0000000000..e1288d502d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.since(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.since), false, + "isConstructor(Temporal.PlainDateTime.prototype.since)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-empty.js new file mode 100644 index 0000000000..8044a80ed1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-empty.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.plaindatetime.prototype.since +description: Empty objects are acceptable +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration( + feb21.since(feb20, {}), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "empty plain object options" +); + +TemporalHelpers.assertDuration( + feb21.since(feb20, () => {}), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "empty function object options" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-invalid.js new file mode 100644 index 0000000000..8e410662d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-invalid.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.plaindatetime.prototype.since +description: A variety of bad options (type error thrown) +features: [Temporal, Symbol] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +const badOptions = [null, 1, 'hello', true, Symbol('foo'), 1n]; +badOptions.forEach((bad) => { + assert.throws( + TypeError, + () => feb21.since(feb20, bad), + `bad options (${typeof bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-undefined.js new file mode 100644 index 0000000000..a5334b31d6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2000, 6, 12, 12, 34, 56, 987, 654, 322); + +const explicit = later.since(earlier, undefined); +assert.sameValue(explicit.years, 0, "default largest unit is days"); +assert.sameValue(explicit.months, 0, "default largest unit is days"); +assert.sameValue(explicit.weeks, 0, "default largest unit is days"); +assert.sameValue(explicit.days, 41, "default largest unit is days"); +assert.sameValue(explicit.nanoseconds, 1, "default smallest unit is nanoseconds and no rounding"); + +const implicit = later.since(earlier); +assert.sameValue(implicit.years, 0, "default largest unit is days"); +assert.sameValue(implicit.months, 0, "default largest unit is days"); +assert.sameValue(implicit.weeks, 0, "default largest unit is days"); +assert.sameValue(implicit.days, 41, "default largest unit is days"); +assert.sameValue(implicit.nanoseconds, 1, "default smallest unit is nanoseconds and no rounding"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/options-wrong-type.js new file mode 100644 index 0000000000..4a19f0ef5f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.since(new Temporal.PlainDateTime(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js new file mode 100644 index 0000000000..aaeca20a9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js @@ -0,0 +1,250 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDateTime + "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.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.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.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", 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(otherDateTimePropertyBag, 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, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.since(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations with identical datetimes"); +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(otherDateTimePropertyBag, 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, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + 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.dateUntil", // 13.m + "call this.calendar.dateAdd", // 13.w MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil", // 10.e +]); +instance.since(otherDateTimePropertyBag, 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(otherDateTimePropertyBag, 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/PlainDateTime/prototype/since/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/prop-desc.js new file mode 100644 index 0000000000..a6cdb6bb4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: The "since" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.since, + "function", + "`typeof PlainDateTime.prototype.since` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "since", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/proto-in-calendar-fields.js new file mode 100644 index 0000000000..4c82a08a7a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.since(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..5aa93cd273 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/read-time-fields-before-datefromfields.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.plaindatetime.prototype.since +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.plaindatetime.prototype.since step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.e: + e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + sec-temporal-interprettemporaldatetimefields steps 1–2: + 1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_). + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321); +const duration = datetime.since({ year: 2021, month: 3, day: 31, calendar }); + +TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 12, 34, 56, 987, 654, 321); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/returns-days.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/returns-days.js new file mode 100644 index 0000000000..ce6ac16027 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/returns-days.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.plaindatetime.prototype.since +description: Days are the default level of specificity +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb_1_2020 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb_1_2021 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration( + feb_1_2021.since(feb_1_2020), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "defaults to returning days (no options)" +); + +TemporalHelpers.assertDuration( + feb_1_2021.since(feb_1_2020, { largestUnit: "auto" }), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "defaults to returning days (largest unit = auto)" +); + +TemporalHelpers.assertDuration( + feb_1_2021.since(feb_1_2020, { largestUnit: "days" }), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "defaults to returning days (largest unit = days)" +); + +const dt = new Temporal.PlainDateTime(2020, 2, 1, 0, 0, 0, 0, 0, 1); + +TemporalHelpers.assertDuration( + dt.since(feb_1_2020), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + "defaults to returning days (nanosecond)" +); + +TemporalHelpers.assertDuration( + feb_1_2021.since(dt), + 0, 0, 0, 365, 23, 59, 59, 999, 999, 999, + "defaults to returning days (nanosecond)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-cross-unit-boundary.js new file mode 100644 index 0000000000..5ce0254b04 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-cross-unit-boundary.js @@ -0,0 +1,36 @@ +// |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.plaindatetime.prototype.since +description: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// Date units +{ + const earlier = new Temporal.PlainDateTime(2022, 1, 1); + const later = new Temporal.PlainDateTime(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"); +} + +// Time units +{ + const earlier = new Temporal.PlainDateTime(2000, 5, 2); + const later = new Temporal.PlainDateTime(2000, 5, 2, 1, 59, 59); + const duration = earlier.since(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" }); + TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, "-1:59 balances to -2 hours"); +} + +// Both +{ + const earlier = new Temporal.PlainDateTime(1970, 1, 1); + const later = new Temporal.PlainDateTime(1971, 12, 31, 23, 59, 59, 999, 999, 999); + const duration = earlier.since(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" }); + TemporalHelpers.assertDuration(duration, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding down 1 ns balances to -2 years"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-negative-duration.js new file mode 100644 index 0000000000..33ded673ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-negative-duration.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.plaindatetime.prototype.since +description: Negative durations are rounded correctly by the modulo operation in NanosecondsToDays +info: | + sec-temporal-nanosecondstodays step 6: + 6. If Type(_relativeTo_) is not Object or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot, then + a. Return the new Record { ..., [[Nanoseconds]]: abs(_nanoseconds_) modulo _dayLengthNs_ × _sign_, ... }. + sec-temporal-roundduration step 6: + 6. If _unit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*, then + ... + d. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). + sec-temporal.plaindatetime.prototype.since step 15: + 15. Let _roundResult_ be ? RoundDuration(−_diff_.[[Years]], −_diff_.[[Months]], −_diff_.[[Weeks]], −_diff_.[[Days]], −_diff_.[[Hours]], −_diff_.[[Minutes]], −_diff_.[[Seconds]], −_diff_.[[Milliseconds]], −_diff_.[[Microseconds]], −_diff_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _dateTime_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12); +const later = new Temporal.PlainDateTime(2000, 5, 5); +const result = later.since(earlier, { smallestUnit: "day", roundingIncrement: 2 }); +TemporalHelpers.assertDuration(result, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-relative-to-receiver.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-relative-to-receiver.js new file mode 100644 index 0000000000..af8a646eb0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/round-relative-to-receiver.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.plaindatetime.prototype.since +description: Values are rounded relative to the receiver +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(2019, 1, 1); +const dt2 = new Temporal.PlainDateTime(2020, 7, 2); + +TemporalHelpers.assertDuration( + dt2.since(dt1, { smallestUnit: "years", roundingMode: "halfExpand" }), + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "rounds relative to the receiver (positive case)" +); + +TemporalHelpers.assertDuration( + dt1.since(dt2, { smallestUnit: "years", roundingMode: "halfExpand" }), + -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "rounds relative to the receiver (negative case)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/rounding-zero-year-month-week-length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/rounding-zero-year-month-week-length.js new file mode 100644 index 0000000000..48be068e79 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 dt1 = new Temporal.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, cal); +const dt2 = new Temporal.PlainDateTime(1971, 1, 1, 0, 0, 0, 0, 0, 1, cal); + +assert.throws(RangeError, () => dt1.since(dt2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => dt1.since(dt2, { smallestUnit: "months" }), "zero month length handled correctly"); +assert.throws(RangeError, () => dt1.since(dt2, { smallestUnit: "weeks" }), "zero week length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-basic.js new file mode 100644 index 0000000000..823ee96147 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-basic.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.plaindatetime.prototype.since +description: Round to different smallest increments +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "hours", roundingIncrement: 3, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 3, 0, 0, 0, 0, 0, + "rounds to an increment of hours" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "minutes", roundingIncrement: 30, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 4, 30, 0, 0, 0,0, + "rounds to an increment of minutes" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "seconds", roundingIncrement: 15, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 4, 17, 0, 0, 0, 0, + "rounds to an increment of seconds" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "milliseconds", roundingIncrement: 10, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 4, 17, 4, 860, 0, 0, + "rounds to an increment of milliseconds" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "microseconds", roundingIncrement: 10, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 4, 17, 4, 864, 200, 0, + "rounds to an increment of microseconds" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "nanoseconds", roundingIncrement: 10, roundingMode: "halfExpand" }), + 0, 0, 0, 973, 4, 17, 4, 864, 197, 530, + "rounds to an increment of nanoseconds" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-cleanly-divides.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-cleanly-divides.js new file mode 100644 index 0000000000..9268e99cd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-cleanly-divides.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.plaindatetime.prototype.since +description: Rounding argument cleanly divides the relevant smallest unit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +[1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { + const options = { smallestUnit: "hours", roundingIncrement }; + assert( + later.since(earlier, options) instanceof Temporal.Duration, + `valid hour increments divide into 24 (rounding increment = ${roundingIncrement}, smallest unit = hours)` + ); +}); + +["minutes", "seconds"].forEach((smallestUnit) => { + [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { + const options = { smallestUnit, roundingIncrement }; + assert( + later.since(earlier, options) instanceof Temporal.Duration, + `valid ${smallestUnit} increments divide into 60 (rounding increment = ${roundingIncrement})` + ); + }); +}); + +["milliseconds", "microseconds", "nanoseconds"].forEach((smallestUnit) => { + [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { + const options = { smallestUnit, roundingIncrement }; + assert( + later.since(earlier, options) instanceof Temporal.Duration, + `valid ${smallestUnit} increments divide into 1000 (rounding increment = ${roundingIncrement})` + ); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-does-not-divide.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-does-not-divide.js new file mode 100644 index 0000000000..7bae2ca7cc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-does-not-divide.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.plaindatetime.prototype.since +description: Throw if rounding increment does not cleanly divide the relevant unit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +const badIncrements = { + "hours": 11, + "minutes": 29, + "seconds": 29, + "milliseconds": 29, + "microseconds": 29, + "nanoseconds": 29 +}; + +Object.entries(badIncrements).forEach(([unit, bad]) => { + assert.throws( + RangeError, + () => later.since(earlier, { smallestUnit: unit, roundingIncrement: bad }), + `throws on increments that do not divide evenly into the next highest (unit = ${unit}, increment = ${bad})` + ); +}); + +const fullIncrements = { + "hours": 24, + "minutes": 60, + "seconds": 60, + "milliseconds": 1000, + "microseconds": 1000, + "nanoseconds": 1000 +}; + +Object.entries(fullIncrements).forEach(([unit, bad]) => { + assert.throws( + RangeError, + () => later.since(earlier, { smallestUnit: unit, roundingIncrement: bad }), + `throws on increments that are equal to the next highest (unit = ${unit}, rounding increment = ${bad}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-nan.js new file mode 100644 index 0000000000..79691a7652 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.prototype.since step 13: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); +assert.throws(RangeError, () => later.since(earlier, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-non-integer.js new file mode 100644 index 0000000000..d2005912fd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +const result = later.since(earlier, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, "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/PlainDateTime/prototype/since/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..0e9d196c8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +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/PlainDateTime/prototype/since/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-undefined.js new file mode 100644 index 0000000000..1e480dd764 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.plaindatetime.prototype.since step 13: + 13. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); + +const explicit = later.since(earlier, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, "default roundingIncrement is 1"); + +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, "default roundingIncrement is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..2602578de8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.prototype.since step 13: + 13. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +includes: [temporalHelpers.js, compareArray.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => later.since(earlier, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 397, 1, 1, 1, 1, 1, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-ceil.js new file mode 100644 index 0000000000..34a5fc36cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-ceil.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [3], [-2]], + ["months", [0, 32], [0, -31]], + ["weeks", [0, 0, 140], [0, 0, -139]], + ["days", [0, 0, 0, 974], [0, 0, 0, -973]], + ["hours", [0, 0, 0, 973, 5], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 18], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -4]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 865], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-expand.js new file mode 100644 index 0000000000..91f7fc35b1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-expand.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 140], [0, 0, -140]], + ["days", [0, 0, 0, 974], [0, 0, 0, -974]], + ["hours", [0, 0, 0, 973, 5], [0, 0, 0, -973, -5]], + ["minutes", [0, 0, 0, 973, 4, 18], [0, 0, 0, -973, -4, -18]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 865], [0, 0, 0, -973, -4, -17, -4, -865]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-floor.js new file mode 100644 index 0000000000..df8eb42a2d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-floor.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [2], [-3]], + ["months", [0, 31], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -140]], + ["days", [0, 0, 0, 973], [0, 0, 0, -974]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -5]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -18]], + ["seconds", [0, 0, 0, 973, 4, 17, 4], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -865]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfCeil.js new file mode 100644 index 0000000000..c6f21e1cd4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfCeil.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfEven.js new file mode 100644 index 0000000000..16af003b07 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfEven.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfExpand.js new file mode 100644 index 0000000000..d9626be1ba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfExpand.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfFloor.js new file mode 100644 index 0000000000..401b03bf04 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfFloor.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..cdcb279d87 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfTrunc.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-halfexpand-default-changes.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfexpand-default-changes.js new file mode 100644 index 0000000000..4a0e3b2bf2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfexpand-default-changes.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.plaindatetime.prototype.since +description: A different default for largest unit will be used if smallest unit is larger than "days" +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "years", roundingMode: "halfExpand" }), + 3, 0, 0, 0, 0, 0, 0, 0, 0,0, + "assumes a different default for largestUnit if smallestUnit is larger than days (smallest unit = years)" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "months", roundingMode: "halfExpand" }), + 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, + "assumes a different default for largestUnit if smallestUnit is larger than days (smallest unit = months)" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "weeks", roundingMode: "halfExpand" }), + 0, 0, 139, 0, 0, 0, 0, 0, 0, 0, + "assumes a different default for largestUnit if smallestUnit is larger than days (smallest unit = weeks)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-invalid-string.js new file mode 100644 index 0000000000..c146e82462 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); +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/PlainDateTime/prototype/since/roundingmode-trunc-is-default.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-trunc-is-default.js new file mode 100644 index 0000000000..5e6bf589be --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-trunc-is-default.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.plaindatetime.prototype.since +description: Truncation (trunc) is the default rounding mode +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "minutes" }), + 0, 0, 0, 973, 4, 17, 0, 0, 0, 0, + "trunc is the default (round up)" +); + +TemporalHelpers.assertDuration( + later.since(earlier, { smallestUnit: "seconds" }), + 0, 0, 0, 973, 4, 17, 4, 0, 0, 0, + "trunc is the default (round down)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-trunc.js new file mode 100644 index 0000000000..d9c74ae636 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-trunc.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 4], [0, 0, 0, -973, -4, -17, -4]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/since/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-undefined.js new file mode 100644 index 0000000000..3e12c14e9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-undefined.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.since +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); + +const explicit1 = later.since(earlier, { smallestUnit: "microsecond", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit1, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, "default roundingMode is trunc"); +const implicit1 = later.since(earlier, { smallestUnit: "microsecond" }); +TemporalHelpers.assertDuration(implicit1, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, "default roundingMode is trunc"); + +const explicit2 = later.since(earlier, { smallestUnit: "millisecond", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit2, 0, 0, 0, 1, 1, 1, 1, 123, 0, 0, "default roundingMode is trunc"); +const implicit2 = later.since(earlier, { smallestUnit: "millisecond" }); +TemporalHelpers.assertDuration(implicit2, 0, 0, 0, 1, 1, 1, 1, 123, 0, 0, "default roundingMode is trunc"); + +const explicit3 = later.since(earlier, { smallestUnit: "second", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit3, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, "default roundingMode is trunc"); +const implicit3 = later.since(earlier, { smallestUnit: "second" }); +TemporalHelpers.assertDuration(implicit3, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, "default roundingMode is trunc"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-wrong-type.js new file mode 100644 index 0000000000..ecae2f1b35 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "trunc", + (roundingMode) => later.since(earlier, { smallestUnit: "microsecond", roundingMode }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/since/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-invalid-string.js new file mode 100644 index 0000000000..36f1d33e50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-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.plaindatetime.prototype.since +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => later.since(earlier, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..5a8b6cda7b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-plurals-accepted.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.plaindatetime.prototype.since +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 12, 13, 35, 57, 988, 655, 322); +const validUnits = [ + "year", + "month", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => later.since(earlier, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-undefined.js new file mode 100644 index 0000000000..7f2571caab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); + +const explicit = later.since(earlier, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 1, 1, 1, 1, 987, 654, 321, "default smallestUnit is nanosecond"); +const implicit = later.since(earlier, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 1, 1, 1, 1, 987, 654, 321, "default smallestUnit is nanosecond"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/smallestunit-wrong-type.js new file mode 100644 index 0000000000..17d4abb27c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "microsecond", + (smallestUnit) => later.since(earlier, { smallestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 1, 1, 1, 987, 654, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/subseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/subseconds.js new file mode 100644 index 0000000000..cfd38c4dfd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/subseconds.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.plaindatetime.prototype.since +description: Returned granularity may be finer than seconds +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2020, 2, 2, 0, 0, 0, 250, 250, 250); + +TemporalHelpers.assertDuration( + feb21.since(feb20, { largestUnit: "milliseconds" }), + 0, 0, 0, 0, 0, 0, 0, 86400250, 250, 250, + "can return subseconds (milliseconds)" +); + +TemporalHelpers.assertDuration( + feb21.since(feb20, { largestUnit: "microseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 86400250250, 250, + "can return subseconds (microseconds)" +); + +TemporalHelpers.assertDuration( + feb21.since(feb20, { largestUnit: "nanoseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 86400250250250, + "can return subseconds (nanoseconds)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/weeks-months-mutually-exclusive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/weeks-months-mutually-exclusive.js new file mode 100644 index 0000000000..6919df2c1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/weeks-months-mutually-exclusive.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.plaindatetime.prototype.since +description: Weeks and months are mutually exclusive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const laterDateTime = dt.add({ days: 42, hours: 3 }); + +TemporalHelpers.assertDuration( + laterDateTime.since(dt, { largestUnit: "weeks" }), + 0, 0, 6, 0, 3, 0, 0, 0, 0, 0, + "weeks and months are mutually exclusive (prefer weeks)" +); + +TemporalHelpers.assertDuration( + laterDateTime.since(dt, { largestUnit: "months" }), + 0, 1, 0, 12, 3, 0, 0, 0,0, 0, + "weeks and months are mutually exclusive (prefer months)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/since/year-zero.js new file mode 100644 index 0000000000..84d2cfd46d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.since +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-12-07", + "-000000-12-07T03:24:30", + "-000000-12-07T03:24:30+01:00", + "-000000-12-07T03:24:30+00:00[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/subtract/ambiguous-date.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.js new file mode 100644 index 0000000000..f23e3f376c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.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.plaindatetime.prototype.subtract +description: Ambiguous subtraction is handled according to the overflow option +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const mar31 = new Temporal.PlainDateTime(2020, 3, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + mar31.subtract({ months: 1 }), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "constrain when ambiguous result (overflow options not supplied)" +); + +TemporalHelpers.assertPlainDateTime( + mar31.subtract({ months: 1 }, { overflow: "constrain" }), + 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0, + "constrain when ambiguous result (overflow options supplied)" +); + +assert.throws( + RangeError, + () => mar31.subtract({ months: 1 }, { overflow: "reject" }), + "throw when ambiguous result with reject" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js new file mode 100644 index 0000000000..7b43031195 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Maximum allowed duration +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1970, 1, 1); + +const maxCases = [ + ["P273790Y8M11DT23H59M59.999999999S", "string with max years"], + [{ years: 273790, months: 8, days: 11, nanoseconds: 86399999999999 }, "property bag with max years"], + ["P3285488M11DT23H59M59.999999999S", "string with max months"], + [{ months: 3285488, days: 11, 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.subtract(arg); + TemporalHelpers.assertPlainDateTime(result, -271821, 4, "M04", 19, 0, 0, 0, 0, 0, 1, `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.assertPlainDateTime(result, 275760, 9, "M09", 13, 23, 59, 59, 999, 999, 999, `operation succeeds with ${descr}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js new file mode 100644 index 0000000000..d5067d41f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Duration-like argument that is out of range +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/subtract/argument-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.js new file mode 100644 index 0000000000..bc8df78a45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.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.plaindatetime.prototype.subtract +description: Duration object arguments are handled +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +const subtractWithDuration = jan31.subtract(new Temporal.Duration(0, 1, 0, 0, 0, 1)); +TemporalHelpers.assertPlainDateTime( + subtractWithDuration, + 2019, 12, "M12", 31, 14, 59, 0, 0, 0, 0, + "Duration argument" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js new file mode 100644 index 0000000000..139dfa66ea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: temporalDurationLike object must contain at least one correctly spelled property +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +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/PlainDateTime/prototype/subtract/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-mixed-sign.js new file mode 100644 index 0000000000..82e4584910 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Positive and negative values in the temporalDurationLike argument are not acceptable +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +["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/PlainDateTime/prototype/subtract/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-not-object.js new file mode 100644 index 0000000000..62a65a3720 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Passing a primitive other than string to subtract() throws +features: [Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +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/PlainDateTime/prototype/subtract/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-singular-properties.js new file mode 100644 index 0000000000..c033a487eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Singular properties in the property bag are always ignored +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); + +[ + { 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/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js new file mode 100644 index 0000000000..ff4eb22bd4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.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.plaindatetime.prototype.subtract +description: Strings with fractional duration units are rounded with the correct rounding mode +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2); + +TemporalHelpers.assertPlainDateTime(datetime.subtract("PT1.03125H"), 2000, 5, "M05", 1, 22, 58, 7, 500, 0, 0, + "positive fractional units rounded with correct rounding mode"); +TemporalHelpers.assertPlainDateTime(datetime.subtract("-PT1.03125H"), 2000, 5, "M05", 2, 1, 1, 52, 500, 0, 0, + "negative fractional units rounded with correct rounding mode"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js new file mode 100644 index 0000000000..d1ce63b571 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Strings with fractional duration units are treated with the correct sign +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2); + +const resultHours = instance.subtract("-PT24.567890123H"); +TemporalHelpers.assertPlainDateTime(resultHours, 2000, 5, "M05", 3, 0, 34, 4, 404, 442, 800, "negative fractional hours"); + +const resultMinutes = instance.subtract("-PT1440.567890123M"); +TemporalHelpers.assertPlainDateTime(resultMinutes, 2000, 5, "M05", 3, 0, 0, 34, 73, 407, 380, "negative fractional minutes"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js new file mode 100644 index 0000000000..53f5e8101a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: A string is parsed into the correct object when passed as the argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); +const result = instance.subtract("P3D"); +TemporalHelpers.assertPlainDateTime(result, 2000, 4, "M04", 29, 0, 34, 56, 987, 654, 321); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js new file mode 100644 index 0000000000..fd8f37b576 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.subtract +description: Negative time fields are balanced upwards +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-addtime step 8: + 8. Return ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_). + sec-temporal-adddatetime step 1: + 1. Let _timeResult_ be ? AddTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). + sec-temporal.plaindatetime.prototype.subtract step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1996, 5, 2, 1, 1, 1, 1, 1, 1); + +const result1 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result1, 1996, 5, "M05", 2, 1, 1, 1, 1, 0, 999, "nanoseconds balance"); + +const result2 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result2, 1996, 5, "M05", 2, 1, 1, 1, 0, 999, 1, "microseconds balance"); + +const result3 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result3, 1996, 5, "M05", 2, 1, 1, 0, 999, 1, 1, "milliseconds balance"); + +const result4 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result4, 1996, 5, "M05", 2, 1, 0, 59, 1, 1, 1, "seconds balance"); + +const result5 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result5, 1996, 5, "M05", 2, 0, 59, 1, 1, 1, 1, "minutes balance"); + +const result6 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 2)); +TemporalHelpers.assertPlainDateTime(result6, 1996, 5, "M05", 1, 23, 1, 1, 1, 1, 1, "hours balance"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js new file mode 100644 index 0000000000..d2bd3b7bef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.subtract +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const subtract = Temporal.PlainDateTime.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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => subtract.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..2e67ff726e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "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/PlainDateTime/prototype/subtract/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin.js new file mode 100644 index 0000000000..2abbf5b33f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.subtract), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.subtract), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.subtract), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.subtract.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js new file mode 100644 index 0000000000..7b6ec5cff6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.subtract +description: PlainDateTime.prototype.subtract should call dateAdd with the appropriate values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +let calls = 0; +class CustomCalendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateAdd(plainDate, duration, options) { + ++calls; + TemporalHelpers.assertPlainDate(plainDate, 2020, 3, "M03", 14, "plainDate argument"); + TemporalHelpers.assertDuration(duration, 0, -10, 0, -1, 0, 0, 0, 0, 0, 0, "duration argument"); + assert.sameValue(typeof options, "object", "options argument: type"); + assert.sameValue(Object.getPrototypeOf(options), null, "options argument: prototype"); + return super.dateAdd(plainDate, duration, options); + } +} + +const plainDateTime = new Temporal.PlainDateTime(2020, 3, 14, 12, 34, 56, 987, 654, 321, new CustomCalendar()); +const result = plainDateTime.subtract({ months: 10, hours: 14 }); +TemporalHelpers.assertPlainDateTime(result, 2019, 5, "M05", 13, 22, 34, 56, 987, 654, 321); +assert.sameValue(calls, 1, "should have called dateAdd"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.js new file mode 100644 index 0000000000..6da61f9205 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.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.plaindatetime.prototype.subtract +description: Testing overflow hours (subtracting hours that push one to the next/previous day) +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102); +const later = new Temporal.PlainDateTime(2020, 5, 31, 23, 12, 38, 271, 986, 102); + +TemporalHelpers.assertPlainDateTime( + dt.subtract({ hours: 12 }), + 2019, 10, "M10", 28, 22, 46, 38, 271, 986, 102, + "subtract result" +); + +TemporalHelpers.assertPlainDateTime( + dt.add({ hours: -12 }), + 2019, 10, "M10", 28, 22, 46, 38, 271, 986, 102, + "hour overflow (pushes to previous day)" +); + +TemporalHelpers.assertPlainDateTime( + later.subtract({ hours: -2 }), + 2020, 6, "M06", 1, 1, 12, 38, 271, 986, 102, + "subtracting a negative amount of hours is equivalent to adding hours" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..b91a8d9857 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.PlainDateTime.prototype.subtract throws a RangeError if any value in a property bag is Infinity +esid: sec-temporal.plaindatetime.prototype.subtract +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +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/PlainDateTime/prototype/subtract/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/length.js new file mode 100644 index 0000000000..ccb418cc58 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.subtract, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.js new file mode 100644 index 0000000000..a71c40fc40 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.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.plaindatetime.prototype.subtract +description: Checking limits of representable PlainDateTime +features: [Temporal] +---*/ + +const min = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1); +const max = new Temporal.PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999); + +["reject", "constrain"].forEach((overflow) => { + assert.throws( + RangeError, + () => min.subtract({ nanoseconds: 1 }, { overflow }), + `subtracting 1 nanosecond beyond minimum limit (overflow = ${overflow})` + ); + assert.throws( + RangeError, + () => max.subtract({ nanoseconds: -1 }, { overflow }), + `subtracting -1 nanosecond beyond maximum limit (overflow = ${overflow})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/name.js new file mode 100644 index 0000000000..beaac9ddae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.subtract, "name", { + value: "subtract", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.js new file mode 100644 index 0000000000..c4bd186e02 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.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.plaindatetime.prototype.subtract +description: Negative durations can be supplied +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.subtract({ minutes: -30 }), + 2020, 1, "M01", 31, 15, 30, 0, 0, 0, 0, + "negative minutes" +); + +TemporalHelpers.assertPlainDateTime( + jan31.subtract({ seconds: -30 }), + 2020, 1, "M01", 31, 15, 0, 30, 0, 0, 0, + "negative seconds" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js new file mode 100644 index 0000000000..e767d44cb7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.PlainDateTime.prototype.subtract throws a RangeError if any value in a property bag is -Infinity +esid: sec-temporal.plaindatetime.prototype.subtract +features: [Temporal] +---*/ + +const overflows = ["constrain", "reject"]; +const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; + +const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +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/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.js new file mode 100644 index 0000000000..d9e9765eb1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: A non-integer value for any recognized property in the property bag, throws a RangeError +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +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/PlainDateTime/prototype/subtract/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/not-a-constructor.js new file mode 100644 index 0000000000..eef1ef6b6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.subtract(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.subtract), false, + "isConstructor(Temporal.PlainDateTime.prototype.subtract)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.js new file mode 100644 index 0000000000..a26714caef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.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.plaindatetime.prototype.subtract +description: Verify that undefined options are handled correctly. +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +TemporalHelpers.assertPlainDateTime( + jan31.subtract({ months: 2 }, {}), + 2019, 11, "M11", 30, 15, 0, 0, 0, 0, 0, + "options may be empty object" +); + +TemporalHelpers.assertPlainDateTime( + jan31.subtract({ months: 2 }, () => {}), + 2019, 11, "M11", 30, 15, 0, 0, 0, 0, 0, + "options may be function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.js new file mode 100644 index 0000000000..9fc78fd1aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.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.plaindatetime.prototype.subtract +description: Various invalid (wrong type) values for options argument +features: [Temporal, Symbol] +---*/ + +const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0); + +const badOptions = [null, 1, 'hello', true, Symbol('foo'), 1n]; + +badOptions.forEach((bad) => { + assert.throws( + TypeError, + () => jan31.subtract({ years: 1 }, bad), + `invalid options (${typeof bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js new file mode 100644 index 0000000000..81f22694a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 3, 31, 12, 34, 56, 987, 654, 321); +const duration = { months: 1 }; + +const explicit = datetime.subtract(duration, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = datetime.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/PlainDateTime/prototype/subtract/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js new file mode 100644 index 0000000000..bea427754a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.subtract({ months: 1 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js new file mode 100644 index 0000000000..2dff5bdcf7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js @@ -0,0 +1,127 @@ +// |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.plaindatetime.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", + // AddDateTime -> 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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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", + // AddDateTime -> 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/PlainDateTime/prototype/subtract/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js new file mode 100644 index 0000000000..65a10f333f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.subtract step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_). +features: [Temporal] +---*/ + +const date = new Temporal.PlainDateTime(2000, 5, 2, 12); +const duration = new Temporal.Duration(3, 3, 0, 3, 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/PlainDateTime/prototype/subtract/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-undefined.js new file mode 100644 index 0000000000..ddcfaf39fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.subtract step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 31, 12); +const duration = new Temporal.Duration(3, 1); + +const explicit = datetime.subtract(duration, { overflow: undefined }); +TemporalHelpers.assertPlainDateTime(explicit, 1997, 4, "M04", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain"); +const implicit = datetime.subtract(duration, {}); +TemporalHelpers.assertPlainDateTime(implicit, 1997, 4, "M04", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js new file mode 100644 index 0000000000..debacd548a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-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.plaindatetime.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-adddatetime step 4: + 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_). + sec-temporal.plaindatetime.prototype.subtract step 5: + 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); +const duration = new Temporal.Duration(3, 3, 0, 3, 3); +TemporalHelpers.checkStringOptionWrongType("overflow", "constrain", + (overflow) => datetime.subtract(duration, { overflow }), + (result, descr) => TemporalHelpers.assertPlainDateTime(result, 1997, 1, "M01", 30, 9, 0, 0, 0, 0, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js new file mode 100644 index 0000000000..19a42d65fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.subtract +description: The "subtract" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.subtract, + "function", + "`typeof PlainDateTime.prototype.subtract` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "subtract", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/subtract/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/subclassing-ignored.js new file mode 100644 index 0000000000..7bc53d362e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.subtract +description: Objects of a subclass are never created as return values for subtract() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "subtract", + [{ nanoseconds: 1 }], + (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 320), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/basic.js new file mode 100644 index 0000000000..08c59f7a6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/basic.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tojson +description: Basic behavior for toJSON +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDateTime(1976, 2, 4, 5, 3, 1), "1976-02-04T05:03:01"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23), "1976-11-18T15:23:00"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30), "1976-11-18T15:23:30"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400), "1976-11-18T15:23:30.1234"], +]; + +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/PlainDateTime/prototype/toJSON/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/branding.js new file mode 100644 index 0000000000..1463d2a4cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tojson +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toJSON = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toJSON.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..d9ab62d1cc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toJSON(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/builtin.js new file mode 100644 index 0000000000..d28100188d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tojson +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toJSON), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toJSON), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toJSON), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toJSON.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/length.js new file mode 100644 index 0000000000..9920ebb9ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tojson +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toJSON, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/name.js new file mode 100644 index 0000000000..6ff7b93cce --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tojson +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toJSON, "name", { + value: "toJSON", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/not-a-constructor.js new file mode 100644 index 0000000000..ed5ee396d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tojson +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toJSON(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toJSON), false, + "isConstructor(Temporal.PlainDateTime.prototype.toJSON)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/prop-desc.js new file mode 100644 index 0000000000..2683d24810 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tojson +description: The "toJSON" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toJSON, + "function", + "`typeof PlainDateTime.prototype.toJSON` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toJSON", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toJSON/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toJSON/year-format.js new file mode 100644 index 0000000000..5f8f2010e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tojson +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDateTime(-100000, 12, 3, 4, 56, 7, 890); +assert.sameValue(instance.toJSON(), "-100000-12-03T04:56:07.89", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-10000, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toJSON(), "-010000-04-05T06:07:08.91", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-9999, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toJSON(), "-009999-06-07T08:09:10.987", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toJSON(), "-001000-08-09T10:09:08.765", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-999, 10, 9, 8, 7, 6, 543); +assert.sameValue(instance.toJSON(), "-000999-10-09T08:07:06.543", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1, 8, 7, 6, 54, 32, 100); +assert.sameValue(instance.toJSON(), "-000001-08-07T06:54:32.1", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(0, 6, 5, 4, 32, 10, 123); +assert.sameValue(instance.toJSON(), "0000-06-05T04:32:10.123", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1, 4, 3, 21, 0, 12, 345); +assert.sameValue(instance.toJSON(), "0001-04-03T21:00:12.345", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(999, 2, 10, 12, 34, 56, 789); +assert.sameValue(instance.toJSON(), "0999-02-10T12:34:56.789", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1000, 1, 23, 4, 56, 7, 890); +assert.sameValue(instance.toJSON(), "1000-01-23T04:56:07.89", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(9999, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toJSON(), "9999-04-05T06:07:08.91", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(10000, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toJSON(), "+010000-06-07T08:09:10.987", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(100000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toJSON(), "+100000-08-09T10:09:08.765", "large positive year formatted as 6-digit"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/branding.js new file mode 100644 index 0000000000..bca2248179 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tolocalestring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toLocaleString = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toLocaleString.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..66f7d218c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toLocaleString(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/builtin.js new file mode 100644 index 0000000000..9f6fcf57ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tolocalestring +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toLocaleString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toLocaleString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toLocaleString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toLocaleString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/length.js new file mode 100644 index 0000000000..25b9d265fb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tolocalestring +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toLocaleString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/name.js new file mode 100644 index 0000000000..51a6a67421 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tolocalestring +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toLocaleString, "name", { + value: "toLocaleString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/not-a-constructor.js new file mode 100644 index 0000000000..1016478185 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tolocalestring +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toLocaleString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toLocaleString), false, + "isConstructor(Temporal.PlainDateTime.prototype.toLocaleString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/prop-desc.js new file mode 100644 index 0000000000..09aa7925af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tolocalestring +description: The "toLocaleString" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toLocaleString, + "function", + "`typeof PlainDateTime.prototype.toLocaleString` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toLocaleString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/return-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/return-string.js new file mode 100644 index 0000000000..e7285c35fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/return-string.js @@ -0,0 +1,17 @@ +// |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.plaindatetime.prototype.tolocalestring +description: > + toLocaleString return a string. +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.sameValue(typeof datetime.toLocaleString("en", { dateStyle: "short" }), "string"); +assert.sameValue(typeof datetime.toLocaleString("en", { timeStyle: "short" }), "string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toLocaleString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toPlainDate/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/branding.js new file mode 100644 index 0000000000..a0f01d67d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/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.plaindatetime.prototype.toplaindate +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainDate = Temporal.PlainDateTime.prototype.toPlainDate; + +assert.sameValue(typeof toPlainDate, "function"); + +assert.throws(TypeError, () => toPlainDate.call(undefined), "undefined"); +assert.throws(TypeError, () => toPlainDate.call(null), "null"); +assert.throws(TypeError, () => toPlainDate.call(true), "true"); +assert.throws(TypeError, () => toPlainDate.call(""), "empty string"); +assert.throws(TypeError, () => toPlainDate.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toPlainDate.call(1), "1"); +assert.throws(TypeError, () => toPlainDate.call({}), "plain object"); +assert.throws(TypeError, () => toPlainDate.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toPlainDate.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/builtin.js new file mode 100644 index 0000000000..a76099be6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplaindate +description: > + Tests that Temporal.PlainDateTime.prototype.toPlainDate + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language Specification. +info: | + Built-in functions that are not constructors do not have a "prototype" property unless + otherwise specified in the description of a particular function. + + Unless specified otherwise, a built-in object that is callable as a function is a built-in + function object with the characteristics described in 10.3. Unless specified otherwise, the + [[Extensible]] internal slot of a built-in object initially has the value true. + + Unless otherwise specified every built-in function and every built-in constructor has the + Function prototype object [...] as the value of its [[Prototype]] internal slot. +features: [Temporal] +---*/ + +assert.sameValue(Object.isExtensible(Temporal.PlainDateTime.prototype.toPlainDate), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toPlainDate), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toPlainDate), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toPlainDate.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/length.js new file mode 100644 index 0000000000..901088a6a1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplaindate +description: Temporal.PlainDateTime.prototype.toPlainDate.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.PlainDateTime.prototype.toPlainDate, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/limits.js new file mode 100644 index 0000000000..aece7cceb8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/limits.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.plaindatetime.prototype.toplaindate +description: toPlainDate works at the edges of the supported range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const min = Temporal.PlainDateTime.from('-271821-04-19T00:00:00.000000001'); +TemporalHelpers.assertPlainDate(min.toPlainDate(), + -271821, 4, "M04", 19, "min"); + +const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); +TemporalHelpers.assertPlainDate(max.toPlainDate(), + 275760, 9, "M09", 13, "max"); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/name.js new file mode 100644 index 0000000000..c63f347aa7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplaindate +description: Temporal.PlainDateTime.prototype.toPlainDate.name is "toPlainDate". +info: | + Every built-in function object, including constructors, that is not identified as an anonymous + function has a "name" property whose value is a String. Unless otherwise specified, this value + is the name that is given to the function in this specification. + + Unless otherwise specified, the "name" property of a built-in function object, if it exists, + has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainDateTime.prototype.toPlainDate, "name", { + value: "toPlainDate", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/not-a-constructor.js new file mode 100644 index 0000000000..3f3871e91b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplaindate +description: > + Temporal.PlainDateTime.prototype.toPlainDate does not implement [[Construct]], is not new-able +info: | + Built-in function objects that are not identified as constructors do not implement the + [[Construct]] internal method unless otherwise specified in the description of a particular + function. +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.throws(TypeError, () => { + new Temporal.PlainDateTime.prototype.toPlainDate(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toPlainDate), false, + "isConstructor(Temporal.PlainDateTime.prototype.toPlainDate)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/prop-desc.js new file mode 100644 index 0000000000..a6d5f85d15 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.toplaindate +description: The "toPlainDate" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toPlainDate, + "function", + "`typeof PlainDateTime.prototype.toPlainDate` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toPlainDate", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainDate/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/branding.js new file mode 100644 index 0000000000..7ae3fd08d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/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.plaindatetime.prototype.toplainmonthday +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainMonthDay = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toPlainMonthDay.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..7b347a4d71 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2023, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toPlainMonthDay(); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..0653113ec6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin-calendar-no-observable-calls.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.plaindatetime.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 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 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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toPlainMonthDay(); + +Object.defineProperty(Temporal.Calendar.prototype, "fields", fieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "monthDayFromFields", monthDayFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/builtin.js new file mode 100644 index 0000000000..90003f6f26 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainMonthDay), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toPlainMonthDay), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toPlainMonthDay), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toPlainMonthDay.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-arguments.js new file mode 100644 index 0000000000..77368791ee --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 456, 789, new CustomCalendar()); +const result = plainDateTime.toPlainMonthDay(); +TemporalHelpers.assertPlainMonthDay(result, "M05", 2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-fields-iterable.js new file mode 100644 index 0000000000..c8e11029a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +datetime.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/PlainDateTime/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..6a7537d9dd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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/PlainDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/calendar-monthdayfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..d464b463c3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: > + Calendar.monthDayFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.toPlainMonthDay(); +assert.sameValue(calendar.monthDayFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..24fa34c241 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.toPlainMonthDay()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/duplicate-calendar-fields.js new file mode 100644 index 0000000000..f0c50f3229 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + + assert.throws(RangeError, () => datetime.toPlainMonthDay()); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/length.js new file mode 100644 index 0000000000..923bb0098e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainMonthDay, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/name.js new file mode 100644 index 0000000000..e4451e029a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainMonthDay, "name", { + value: "toPlainMonthDay", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/not-a-constructor.js new file mode 100644 index 0000000000..7a8546b6ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainmonthday +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainMonthDay(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toPlainMonthDay), false, + "isConstructor(Temporal.PlainDateTime.prototype.toPlainMonthDay)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/prop-desc.js new file mode 100644 index 0000000000..e240362c1e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/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.plaindatetime.prototype.toplainmonthday +description: The "toPlainMonthDay" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toPlainMonthDay, + "function", + "`typeof PlainDateTime.prototype.toPlainMonthDay` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toPlainMonthDay", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/proto-in-calendar-fields.js new file mode 100644 index 0000000000..482bbf5603 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.toPlainMonthDay()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainMonthDay/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toPlainTime/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/basic.js new file mode 100644 index 0000000000..319fc1ec88 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/basic.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.plaindatetime.prototype.toplaintime +description: Basic usage +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const plainDateTime = Temporal.PlainDateTime.from("2020-02-12T11:42:56.987654321+01:00[Europe/Amsterdam]"); +TemporalHelpers.assertPlainTime(plainDateTime.toPlainTime(), 11, 42, 56, 987, 654, 321); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/branding.js new file mode 100644 index 0000000000..40602b80ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainTime = Temporal.PlainDateTime.prototype.toPlainTime; + +assert.sameValue(typeof toPlainTime, "function"); + +assert.throws(TypeError, () => toPlainTime.call(undefined), "undefined"); +assert.throws(TypeError, () => toPlainTime.call(null), "null"); +assert.throws(TypeError, () => toPlainTime.call(true), "true"); +assert.throws(TypeError, () => toPlainTime.call(""), "empty string"); +assert.throws(TypeError, () => toPlainTime.call(Symbol()), "symbol"); +assert.throws(TypeError, () => toPlainTime.call(1), "1"); +assert.throws(TypeError, () => toPlainTime.call({}), "plain object"); +assert.throws(TypeError, () => toPlainTime.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toPlainTime.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/builtin.js new file mode 100644 index 0000000000..86434ef219 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: > + Tests that Temporal.PlainDateTime.prototype.toPlainTime + 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.PlainDateTime.prototype.toPlainTime), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toPlainTime), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toPlainTime), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toPlainTime.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/length.js new file mode 100644 index 0000000000..46609cbece --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: Temporal.PlainDateTime.prototype.toPlainTime.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.PlainDateTime.prototype.toPlainTime, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/name.js new file mode 100644 index 0000000000..690ec0d448 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: Temporal.PlainDateTime.prototype.toPlainTime.name is "toPlainTime". +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.PlainDateTime.prototype.toPlainTime, "name", { + value: "toPlainTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/not-a-constructor.js new file mode 100644 index 0000000000..6f82f65253 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: > + Temporal.PlainDateTime.prototype.toPlainTime 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.PlainDateTime.prototype.toPlainTime(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toPlainTime), false, + "isConstructor(Temporal.PlainDateTime.prototype.toPlainTime)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/prop-desc.js new file mode 100644 index 0000000000..33c7fe422b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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.plaindatetime.prototype.toplaintime +description: The "toPlainTime" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toPlainTime, + "function", + "`typeof PlainDateTime.prototype.toPlainTime` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toPlainTime", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainTime/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/PlainDateTime/prototype/toPlainYearMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/branding.js new file mode 100644 index 0000000000..ebd23a5016 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/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.plaindatetime.prototype.toplainyearmonth +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toPlainYearMonth = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toPlainYearMonth.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..d5a326f4d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2023, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toPlainYearMonth(); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..bfcd5570e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin-calendar-no-observable-calls.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.plaindatetime.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 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 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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toPlainYearMonth(); + +Object.defineProperty(Temporal.Calendar.prototype, "fields", fieldsOriginal); +Object.defineProperty(Temporal.Calendar.prototype, "yearMonthFromFields", yearMonthFromFieldsOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/builtin.js new file mode 100644 index 0000000000..6728798787 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainYearMonth), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toPlainYearMonth), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toPlainYearMonth), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toPlainYearMonth.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-arguments.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-arguments.js new file mode 100644 index 0000000000..fb4b716c49 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 456, 789, new CustomCalendar()); +const result = plainDateTime.toPlainYearMonth(); +TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-fields-iterable.js new file mode 100644 index 0000000000..d799f96e4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +datetime.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/PlainDateTime/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..769b532980 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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/PlainDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..a51139bca0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: > + Calendar.yearMonthFromFields method is called with undefined as the options + value when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.toPlainYearMonth(); +assert.sameValue(calendar.yearMonthFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..ae3cdb87c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.toPlainYearMonth()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/duplicate-calendar-fields.js new file mode 100644 index 0000000000..55446f83eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + + assert.throws(RangeError, () => datetime.toPlainYearMonth()); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/length.js new file mode 100644 index 0000000000..1ae6d9efd2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainYearMonth, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/name.js new file mode 100644 index 0000000000..b2365b219d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainYearMonth, "name", { + value: "toPlainYearMonth", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/not-a-constructor.js new file mode 100644 index 0000000000..d6bb102ce7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.toplainyearmonth +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toPlainYearMonth(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toPlainYearMonth), false, + "isConstructor(Temporal.PlainDateTime.prototype.toPlainYearMonth)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/prop-desc.js new file mode 100644 index 0000000000..955de19a0b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/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.plaindatetime.prototype.toplainyearmonth +description: The "toPlainYearMonth" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toPlainYearMonth, + "function", + "`typeof PlainDateTime.prototype.toPlainYearMonth` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toPlainYearMonth", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/proto-in-calendar-fields.js new file mode 100644 index 0000000000..fb38edd6f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.toPlainYearMonth()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toPlainYearMonth/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toString/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/basic.js new file mode 100644 index 0000000000..274774ef8f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/basic.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Checking the string form of an explicitly constructed instance with all arguments +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); + +assert.sameValue(datetime.toString(), "1976-11-18T15:23:30.123456789", "check string value"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/branding.js new file mode 100644 index 0000000000..2758458150 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toString = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toString.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..a24cc7c036 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.toString(); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/builtin.js new file mode 100644 index 0000000000..d6db5a1527 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendar-tostring.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendar-tostring.js new file mode 100644 index 0000000000..b64c3599cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, customCalendar); +[ + ["always", "2000-05-02T12:34:56.987654321[u-ca=custom]", 1], + ["auto", "2000-05-02T12:34:56.987654321[u-ca=custom]", 1], + ["critical", "2000-05-02T12:34:56.987654321[!u-ca=custom]", 1], + ["never", "2000-05-02T12:34:56.987654321", 0], + [undefined, "2000-05-02T12:34:56.987654321[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/PlainDateTime/prototype/toString/calendarname-always.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-always.js new file mode 100644 index 0000000000..6c251461e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 = [ + [[], "1976-11-18T15:23:00[u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 0, 0, 0, 0, ...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/PlainDateTime/prototype/toString/calendarname-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-auto.js new file mode 100644 index 0000000000..7b5ebf5e4c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 = [ + [[], "1976-11-18T15:23:00", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "1976-11-18T15:23:00", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 0, 0, 0, 0, ...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/PlainDateTime/prototype/toString/calendarname-critical.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-critical.js new file mode 100644 index 0000000000..b1846de272 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 = [ + [[], "1976-11-18T15:23:00[!u-ca=iso8601]", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "1976-11-18T15:23:00[!u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "1976-11-18T15:23:00[!u-ca=iso8601]", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "1976-11-18T15:23:00[!u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "1976-11-18T15:23:00[!u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 0, 0, 0, 0, ...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/PlainDateTime/prototype/toString/calendarname-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-invalid-string.js new file mode 100644 index 0000000000..bdd5ed36cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.protoype.tostring step 6: + 6. Let _showCalendar_ be ? ToShowCalendarOption(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const invalidValues = ["ALWAYS", "sometimes", "other string", "auto\0"]; + +for (const calendarName of invalidValues) { + assert.throws( + RangeError, + () => datetime.toString({ calendarName }), + `${calendarName} is an invalid value for calendarName option` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-never.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-never.js new file mode 100644 index 0000000000..8c5215fa0b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 = [ + [[], "1976-11-18T15:23:00", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "1976-11-18T15:23:00", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "1976-11-18T15:23:00", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "1976-11-18T15:23:00", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "1976-11-18T15:23:00", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const date = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 0, 0, 0, 0, ...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/PlainDateTime/prototype/toString/calendarname-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-undefined.js new file mode 100644 index 0000000000..a888d1c815 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.protoype.tostring step 6: + 6. 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 = [ + [[], "1976-11-18T15:23:00", "built-in ISO"], + [[{ id: "custom", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=custom]", "custom"], + [[{ id: "iso8601", ...calendarMethods }], "1976-11-18T15:23:00", "custom with iso8601 id"], + [[{ id: "ISO8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=ISO8601]", "custom with caps id"], + [[{ id: "\u0131so8601", ...calendarMethods }], "1976-11-18T15:23:00[u-ca=\u0131so8601]", "custom with dotless i id"], +]; + +for (const [args, expected, description] of tests) { + const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 0, 0, 0, 0, ...args); + const result = datetime.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/PlainDateTime/prototype/toString/calendarname-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/calendarname-wrong-type.js new file mode 100644 index 0000000000..12b13a24cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.protoype.tostring step 6: + 6. 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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); + +TemporalHelpers.checkStringOptionWrongType("calendarName", "auto", + (calendarName) => datetime.toString({ calendarName }), + (result, descr) => assert.sameValue(result, "2000-05-02T12:34:56.987654321[u-ca=custom]", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.js new file mode 100644 index 0000000000..9bee10c937 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-auto.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.plaindatetime.prototype.tostring +description: auto value for fractionalSecondDigits option +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDateTime(1976, 2, 4, 5, 3, 1), "1976-02-04T05:03:01"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23), "1976-11-18T15:23:00"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30), "1976-11-18T15:23:30"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400), "1976-11-18T15:23:30.1234"], +]; + +for (const [datetime, expected] of tests) { + assert.sameValue(datetime.toString(), expected, "default is to emit seconds and drop trailing zeroes"); + assert.sameValue(datetime.toString({ fractionalSecondDigits: "auto" }), expected, "auto is the default"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js new file mode 100644 index 0000000000..917c2d7a48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.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.plaindatetime.prototype.tostring +description: RangeError thrown when fractionalSecondDigits option not one of the allowed string values +info: | + sec-getstringornumberoption step 4: + 4. If _stringValues_ is not *undefined* and _stringValues_ does not contain an element equal to _value_, throw a *RangeError* exception. + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); + +for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) { + assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits }), + `"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-nan.js new file mode 100644 index 0000000000..05e1133aa9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-nan.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.plaindatetime.prototype.tostring +description: RangeError thrown when fractionalSecondDigits option is NaN +info: | + sec-getoption step 8.b: + b. If _value_ is *NaN*, throw a *RangeError* exception. + sec-getstringornumberoption step 2: + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js new file mode 100644 index 0000000000..38444c4b52 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.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.plaindatetime.prototype.tostring +description: Rounding for fractionalSecondDigits option +info: | + sec-getstringornumberoption step 3.b: + b. Return floor(ℝ(_value_)). + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); + +let string = datetime.toString({ fractionalSecondDigits: 2.5 }); +assert.sameValue(string, "2000-05-02T12:34:56.98", "fractionalSecondDigits 2.5 floors to 2"); + +string = datetime.toString({ fractionalSecondDigits: 9.7 }); +assert.sameValue(string, "2000-05-02T12:34:56.987650000", "fractionalSecondDigits 9.7 floors to 9 and is not out of range"); + +assert.throws( + RangeError, + () => datetime.toString({ fractionalSecondDigits: -0.6 }), + "fractionalSecondDigits -0.6 floors to -1 and is out of range" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.js new file mode 100644 index 0000000000..41eb31d42d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-number.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.plaindatetime.prototype.tostring +description: Number for fractionalSecondDigits option +features: [Temporal] +---*/ + +const fewSeconds = new Temporal.PlainDateTime(1976, 2, 4, 5, 3, 1); +const zeroSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); +const wholeSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30); +const subSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400); + +assert.sameValue(fewSeconds.toString({ fractionalSecondDigits: 0 }), "1976-02-04T05:03:01", + "pads parts with 0"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 0 }), "1976-11-18T15:23:30", + "truncates 4 decimal places to 0"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:00.00", + "pads zero seconds to 2 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:30.00", + "pads whole seconds to 2 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 2 }), "1976-11-18T15:23:30.12", + "truncates 4 decimal places to 2"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 3 }), "1976-11-18T15:23:30.123", + "truncates 4 decimal places to 3"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 6 }), "1976-11-18T15:23:30.123400", + "pads 4 decimal places to 6"); +assert.sameValue(zeroSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:00.0000000", + "pads zero seconds to 7 decimal places"); +assert.sameValue(wholeSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:30.0000000", + "pads whole seconds to 7 decimal places"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 7 }), "1976-11-18T15:23:30.1234000", + "pads 4 decimal places to 7"); +assert.sameValue(subSeconds.toString({ fractionalSecondDigits: 9 }), "1976-11-18T15:23:30.123400000", + "pads 4 decimal places to 9"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js new file mode 100644 index 0000000000..945bad9c44 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.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.plaindatetime.prototype.tostring +description: RangeError thrown when fractionalSecondDigits option out of range +info: | + sec-getstringornumberoption step 3.a: + a. If _value_ < _minimum_ or _value_ > _maximum_, throw a *RangeError* exception. + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); + +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -Infinity }), + "−∞ is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }), + "−1 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }), + "10 is out of range for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: Infinity }), + "∞ is out of range for fractionalSecondDigits"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js new file mode 100644 index 0000000000..a46b0f4e13 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.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.plaindatetime.prototype.tostring +description: Fallback value for fractionalSecondDigits option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-getstringornumberoption step 2: + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +features: [Temporal] +---*/ + +const tests = [ + [new Temporal.PlainDateTime(1976, 2, 4, 5, 3, 1), "1976-02-04T05:03:01"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23), "1976-11-18T15:23:00"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30), "1976-11-18T15:23:30"], + [new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400), "1976-11-18T15:23:30.1234"], +]; + +for (const [datetime, expected] of tests) { + const explicit = datetime.toString({ fractionalSecondDigits: undefined }); + assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)"); + + const implicit = datetime.toString({}); + assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)"); + + const lambda = datetime.toString(() => {}); + assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js new file mode 100644 index 0000000000..f803a9978d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.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.plaindatetime.prototype.tostring +description: Type conversions for fractionalSecondDigits option +info: | + sec-getoption steps 8–9: + 8. Else if _type_ is Number, then + a. Set _value_ to ? ToNumber(value). + b. ... + 9. Else, + a. Set _value_ to ? ToString(value). + sec-getstringornumberoption step 2: + 2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_). + sec-temporal-tosecondsstringprecision step 9: + 9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*). + sec-temporal.plaindatetime.prototype.tostring step 4: + 4. Let _precision_ be ? ToSecondsStringPrecision(_options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); + +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: null }), + "null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: true }), + "true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: false }), + "false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits"); +assert.throws(TypeError, () => datetime.toString({ fractionalSecondDigits: Symbol() }), + "symbols are not numbers and cannot convert to strings"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 2n }), + "bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits"); +assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: {} }), + "plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits"); + +const expected = [ + "get fractionalSecondDigits.toString", + "call fractionalSecondDigits.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits"); +const result = datetime.toString({ fractionalSecondDigits: observer }); +assert.sameValue(result, "2000-05-02T12:34:56.98765", "object with toString uses toString return value"); +assert.compareArray(actual, expected, "object with toString calls toString and not valueOf"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/length.js new file mode 100644 index 0000000000..9b5b4a9165 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/name.js new file mode 100644 index 0000000000..cd3fe445d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toString, "name", { + value: "toString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/not-a-constructor.js new file mode 100644 index 0000000000..82930cfe3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toString), false, + "isConstructor(Temporal.PlainDateTime.prototype.toString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-object.js new file mode 100644 index 0000000000..d0c5ebe101 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: Empty or a function object may be used as options +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2); + +const result1 = instance.toString({}); +assert.sameValue( + result1, "2000-05-02T00:00:00", + "options may be an empty plain object" +); + +const result2 = instance.toString(() => {}); +assert.sameValue( + result2, "2000-05-02T00:00:00", + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-undefined.js new file mode 100644 index 0000000000..23248ad28c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-undefined.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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 datetime1 = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0); +const datetime2 = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0, calendar); + +[ + [datetime1, "2000-05-02T12:34:56.98765"], + [datetime2, "2000-05-02T12:34:56.98765[u-ca=custom]"], +].forEach(([datetime, expected]) => { + const explicit = datetime.toString(undefined); + assert.sameValue(explicit, expected, "default calendarName option is auto, precision is auto, and no rounding"); + + const propertyImplicit = datetime.toString({}); + assert.sameValue(propertyImplicit, expected, "default calendarName option is auto, precision is auto, and no rounding"); + + const implicit = datetime.toString(); + assert.sameValue(implicit, expected, "default calendarName option is auto, precision is auto, and no rounding"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/options-wrong-type.js new file mode 100644 index 0000000000..b473818edd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toString(value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/order-of-operations.js new file mode 100644 index 0000000000..fa47dcb179 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/order-of-operations.js @@ -0,0 +1,70 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Properties on objects 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 options.fractionalSecondDigits", + "get options.fractionalSecondDigits.toString", + "call options.fractionalSecondDigits.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get this.calendar.id", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDateTime(1990, 11, 3, 15, 54, 37, 123, 456, 789, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +instance.toString( + TemporalHelpers.propertyBagObserver(actual, { + fractionalSecondDigits: "auto", + roundingMode: "halfExpand", + smallestUnit: "millisecond", + calendarName: "auto", + }, "options"), +); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +// Same as above but without options.smallestUnit.toString +const expectedForFractionalSecondDigits = [ + "get options.calendarName", + "get options.calendarName.toString", + "call options.calendarName.toString", + "get options.fractionalSecondDigits", + "get options.fractionalSecondDigits.toString", + "call options.fractionalSecondDigits.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.smallestUnit", + "get this.calendar.id", +]; + +instance.toString( + TemporalHelpers.propertyBagObserver(actual, { + fractionalSecondDigits: "auto", + roundingMode: "halfExpand", + smallestUnit: undefined, + calendarName: "auto", + }, "options"), +); +assert.compareArray(actual, expectedForFractionalSecondDigits, "order of operations with smallestUnit undefined"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/prop-desc.js new file mode 100644 index 0000000000..8206cc471b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: The "toString" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toString, + "function", + "`typeof PlainDateTime.prototype.toString` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.js new file mode 100644 index 0000000000..a2c73e27e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-cross-midnight.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.plaindatetime.prototype.tostring +description: Rounding can cross midnight +features: [Temporal] +---*/ + +const plainDateTime = new Temporal.PlainDateTime(1999, 12, 31, 23, 59, 59, 999, 999, 999); // one nanosecond before 2000-01-01T00:00:00 +for (const roundingMode of ["ceil", "halfExpand"]) { + assert.sameValue(plainDateTime.toString({ fractionalSecondDigits: 8, roundingMode }), "2000-01-01T00:00:00.00000000"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.js new file mode 100644 index 0000000000..334db9466f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/rounding-direction.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.plaindatetime.prototype.tostring +description: Rounding down is towards the Big Bang, not the epoch or 1 BCE +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(-99, 12, 15, 12, 0, 0, 500); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "floor" }), + "-000099-12-15T12:00:00", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "trunc" }), + "-000099-12-15T12:00:00", + "Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "ceil" }), + "-000099-12-15T12:00:01", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode ceil)" +); +assert.sameValue( + instance.toString({ smallestUnit: "second", roundingMode: "halfExpand" }), + "-000099-12-15T12:00:01", + "Rounding up is away from the Big Bang, not the epoch or 1 BCE (roundingMode halfExpand)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.js new file mode 100644 index 0000000000..4a60e4aaa9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-ceil.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.plaindatetime.prototype.tostring +description: ceil value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "ceil" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is ceil (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "ceil" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is ceil (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "ceil" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is ceil (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "ceil" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is ceil (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "ceil" }); +assert.sameValue(result5, "2000-05-02T12:34:57", + "roundingMode is ceil (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "ceil" }); +assert.sameValue(result6, "2000-05-02T12:34:57", + "roundingMode is ceil (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "ceil" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is ceil (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-expand.js new file mode 100644 index 0000000000..44ef84dea2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-expand.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.plaindatetime.prototype.tostring +description: expand value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "expand" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is expand (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "expand" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is expand (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "expand" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is expand (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "expand" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is expand (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "expand" }); +assert.sameValue(result5, "2000-05-02T12:34:57", + "roundingMode is expand (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "expand" }); +assert.sameValue(result6, "2000-05-02T12:34:57", + "roundingMode is expand (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "expand" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is expand (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.js new file mode 100644 index 0000000000..1505b99ac5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-floor.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.plaindatetime.prototype.tostring +description: floor value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "floor" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is floor (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "floor" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is floor (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "floor" }); +assert.sameValue(result3, "2000-05-02T12:34:56.123", + "roundingMode is floor (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "floor" }); +assert.sameValue(result4, "2000-05-02T12:34:56.123", + "roundingMode is floor (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "floor" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is floor (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "floor" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is floor (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "floor" }); +assert.sameValue(result7, "2000-05-02T12:34", "roundingMode is floor (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfCeil.js new file mode 100644 index 0000000000..4db75c3bc6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfCeil.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.plaindatetime.prototype.tostring +description: halfCeil value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfCeil" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is halfCeil (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfCeil" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is halfCeil (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfCeil" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfCeil (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfCeil" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfCeil (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfCeil" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfCeil (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfCeil" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfCeil (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfCeil" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfCeil (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfEven.js new file mode 100644 index 0000000000..84d09a9bae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfEven.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.plaindatetime.prototype.tostring +description: halfEven value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfEven" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is halfEven (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfEven" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is halfEven (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfEven" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfEven (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfEven" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfEven (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfEven" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfEven (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfEven" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfEven (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfEven" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfEven (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.js new file mode 100644 index 0000000000..4ef2194248 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfExpand.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.plaindatetime.prototype.tostring +description: halfExpand value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfExpand" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfExpand" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123988", + "roundingMode is halfExpand (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfExpand" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfExpand (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfExpand" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfExpand (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfExpand" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfExpand (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfExpand" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfExpand (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfExpand" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfExpand (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfFloor.js new file mode 100644 index 0000000000..eb10bd3589 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfFloor.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.plaindatetime.prototype.tostring +description: halfFloor value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfFloor" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is halfFloor (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfFloor" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is halfFloor (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfFloor" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfFloor (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfFloor" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfFloor (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfFloor" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfFloor (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfFloor" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfFloor (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfFloor" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfFloor (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..ecad87495c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-halfTrunc.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.plaindatetime.prototype.tostring +description: halfTrunc value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "halfTrunc" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is halfTrunc (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "halfTrunc" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is halfTrunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "halfTrunc" }); +assert.sameValue(result3, "2000-05-02T12:34:56.124", + "roundingMode is halfTrunc (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "halfTrunc" }); +assert.sameValue(result4, "2000-05-02T12:34:56.124", + "roundingMode is halfTrunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "halfTrunc" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is halfTrunc (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "halfTrunc" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is halfTrunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "halfTrunc" }); +assert.sameValue(result7, "2000-05-02T12:35", "roundingMode is halfTrunc (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-invalid-string.js new file mode 100644 index 0000000000..f9e6668145 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-invalid-string.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +for (const roundingMode of ["other string", "cile", "CEIL", "ce\u0131l", "auto", "halfexpand", "floor\0"]) { + assert.throws(RangeError, () => datetime.toString({ smallestUnit: "microsecond", roundingMode })); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.js new file mode 100644 index 0000000000..12080ca5cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-trunc.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.plaindatetime.prototype.tostring +description: trunc value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const result1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: "trunc" }); +assert.sameValue(result1, "2000-05-02T12:34:56.123987", + "roundingMode is trunc (with 6 digits from smallestUnit)"); + +const result2 = datetime.toString({ fractionalSecondDigits: 6, roundingMode: "trunc" }); +assert.sameValue(result2, "2000-05-02T12:34:56.123987", + "roundingMode is trunc (with 6 digits from fractionalSecondDigits)"); + +const result3 = datetime.toString({ smallestUnit: "millisecond", roundingMode: "trunc" }); +assert.sameValue(result3, "2000-05-02T12:34:56.123", + "roundingMode is trunc (with 3 digits from smallestUnit)"); + +const result4 = datetime.toString({ fractionalSecondDigits: 3, roundingMode: "trunc" }); +assert.sameValue(result4, "2000-05-02T12:34:56.123", + "roundingMode is trunc (with 3 digits from fractionalSecondDigits)"); + +const result5 = datetime.toString({ smallestUnit: "second", roundingMode: "trunc" }); +assert.sameValue(result5, "2000-05-02T12:34:56", + "roundingMode is trunc (with 0 digits from smallestUnit)"); + +const result6 = datetime.toString({ fractionalSecondDigits: 0, roundingMode: "trunc" }); +assert.sameValue(result6, "2000-05-02T12:34:56", + "roundingMode is trunc (with 0 digits from fractionalSecondDigits)"); + +const result7 = datetime.toString({ smallestUnit: "minute", roundingMode: "trunc" }); +assert.sameValue(result7, "2000-05-02T12:34", "roundingMode is trunc (round to minute)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-undefined.js new file mode 100644 index 0000000000..9cd034c843 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Fallback value for roundingMode option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const explicit1 = datetime.toString({ smallestUnit: "microsecond", roundingMode: undefined }); +assert.sameValue(explicit1, "2000-05-02T12:34:56.123987", "default roundingMode is trunc"); +const implicit1 = datetime.toString({ smallestUnit: "microsecond" }); +assert.sameValue(implicit1, "2000-05-02T12:34:56.123987", "default roundingMode is trunc"); + +const explicit2 = datetime.toString({ smallestUnit: "millisecond", roundingMode: undefined }); +assert.sameValue(explicit2, "2000-05-02T12:34:56.123", "default roundingMode is trunc"); +const implicit2 = datetime.toString({ smallestUnit: "millisecond" }); +assert.sameValue(implicit2, "2000-05-02T12:34:56.123", "default roundingMode is trunc"); + +const explicit3 = datetime.toString({ smallestUnit: "second", roundingMode: undefined }); +assert.sameValue(explicit3, "2000-05-02T12:34:56", "default roundingMode is trunc"); +const implicit3 = datetime.toString({ smallestUnit: "second" }); +assert.sameValue(implicit3, "2000-05-02T12:34:56", "default roundingMode is trunc"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-wrong-type.js new file mode 100644 index 0000000000..c876d5e65a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/roundingmode-wrong-type.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.plaindatetime.prototype.tostring +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "trunc", + (roundingMode) => datetime.toString({ smallestUnit: "microsecond", roundingMode }), + (result, descr) => assert.sameValue(result, "2000-05-02T12:34:56.123987", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.js new file mode 100644 index 0000000000..fae1c3a786 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-fractionalseconddigits.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.plaindatetime.prototype.tostring +description: fractionalSecondDigits option is not used with smallestUnit present +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 12, 34, 56, 789, 999, 999); +const tests = [ + ["minute", "1976-11-18T12:34"], + ["second", "1976-11-18T12:34:56"], + ["millisecond", "1976-11-18T12:34:56.789"], + ["microsecond", "1976-11-18T12:34:56.789999"], + ["nanosecond", "1976-11-18T12:34:56.789999999"], +]; + +for (const [smallestUnit, expected] of tests) { + const string = datetime.toString({ + smallestUnit, + fractionalSecondDigits: 5, + }); + assert.sameValue(string, expected, `smallestUnit: "${smallestUnit}" overrides fractionalSecondDigits`); +} + +assert.throws(RangeError, () => datetime.toString({ + smallestUnit: "hour", + fractionalSecondDigits: 5, +}), "hour is an invalid smallestUnit but still overrides fractionalSecondDigits"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-string.js new file mode 100644 index 0000000000..81d11967a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-invalid-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.plaindatetime.prototype.tostring +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +const badValues = [ + "era", + "eraYear", + "year", + "month", + "week", + "day", + "hour", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "years", + "months", + "weeks", + "days", + "hours", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..f5eb54beea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/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.plaindatetime.prototype.tostring +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 789, 999, 999); +const validUnits = [ + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => datetime.toString({ smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-undefined.js new file mode 100644 index 0000000000..b10e795149 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-undefined.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.plaindatetime.prototype.tostring +description: Fallback value for smallestUnit option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); + +const explicit1 = datetime.toString({ smallestUnit: undefined, fractionalSecondDigits: 6 }); +assert.sameValue(explicit1, "2000-05-02T12:34:56.123987", "default smallestUnit defers to fractionalSecondDigits"); +const implicit1 = datetime.toString({ fractionalSecondDigits: 6 }); +assert.sameValue(implicit1, "2000-05-02T12:34:56.123987", "default smallestUnit defers to fractionalSecondDigits"); + +const explicit2 = datetime.toString({ smallestUnit: undefined, fractionalSecondDigits: 3 }); +assert.sameValue(explicit2, "2000-05-02T12:34:56.123", "default smallestUnit defers to fractionalSecondDigits"); +const implicit2 = datetime.toString({ fractionalSecondDigits: 3 }); +assert.sameValue(implicit2, "2000-05-02T12:34:56.123", "default smallestUnit defers to fractionalSecondDigits"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js new file mode 100644 index 0000000000..d766cba089 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tostring +description: Valid units for the smallestUnit option +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 456, 789); + +function test(instance, expectations, description) { + for (const [smallestUnit, expectedResult] of expectations) { + assert.sameValue(instance.toString({ smallestUnit }), expectedResult, + `${description} with smallestUnit "${smallestUnit}"`); + } +} + +test( + datetime, + [ + ["minute", "2000-05-02T12:34"], + ["second", "2000-05-02T12:34:56"], + ["millisecond", "2000-05-02T12:34:56.123"], + ["microsecond", "2000-05-02T12:34:56.123456"], + ["nanosecond", "2000-05-02T12:34:56.123456789"], + ], + "subseconds toString" +); + +test( + new Temporal.PlainDateTime(2000, 5, 2, 12, 34), + [ + ["minute", "2000-05-02T12:34"], + ["second", "2000-05-02T12:34:00"], + ["millisecond", "2000-05-02T12:34:00.000"], + ["microsecond", "2000-05-02T12:34:00.000000"], + ["nanosecond", "2000-05-02T12:34:00.000000000"], + ], + "whole minutes toString" +); + +const notValid = [ + "era", + "year", + "month", + "week", + "day", + "hour", +]; + +notValid.forEach((smallestUnit) => { + assert.throws(RangeError, () => datetime.toString({ smallestUnit }), + `"${smallestUnit}" is not a valid unit for the smallestUnit option`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-wrong-type.js new file mode 100644 index 0000000000..3a6a294126 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-wrong-type.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.plaindatetime.prototype.tostring +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "microsecond", + (smallestUnit) => datetime.toString({ smallestUnit }), + (result, descr) => assert.sameValue(result, "2000-05-02T12:34:56.123987", descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/year-format.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toString/year-format.js new file mode 100644 index 0000000000..5815ef6a99 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tostring +description: Verify that the year is appropriately formatted as 4 or 6 digits +features: [Temporal] +---*/ + +let instance = new Temporal.PlainDateTime(-100000, 12, 3, 4, 56, 7, 890); +assert.sameValue(instance.toString(), "-100000-12-03T04:56:07.89", "large negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-10000, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toString(), "-010000-04-05T06:07:08.91", "smallest 5-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-9999, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toString(), "-009999-06-07T08:09:10.987", "largest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toString(), "-001000-08-09T10:09:08.765", "smallest 4-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-999, 10, 9, 8, 7, 6, 543); +assert.sameValue(instance.toString(), "-000999-10-09T08:07:06.543", "largest 3-digit negative year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(-1, 8, 7, 6, 54, 32, 100); +assert.sameValue(instance.toString(), "-000001-08-07T06:54:32.1", "year -1 formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(0, 6, 5, 4, 32, 10, 123); +assert.sameValue(instance.toString(), "0000-06-05T04:32:10.123", "year 0 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1, 4, 3, 21, 0, 12, 345); +assert.sameValue(instance.toString(), "0001-04-03T21:00:12.345", "year 1 formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(999, 2, 10, 12, 34, 56, 789); +assert.sameValue(instance.toString(), "0999-02-10T12:34:56.789", "largest 3-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(1000, 1, 23, 4, 56, 7, 890); +assert.sameValue(instance.toString(), "1000-01-23T04:56:07.89", "smallest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(9999, 4, 5, 6, 7, 8, 910); +assert.sameValue(instance.toString(), "9999-04-05T06:07:08.91", "largest 4-digit positive year formatted as 4-digit"); + +instance = new Temporal.PlainDateTime(10000, 6, 7, 8, 9, 10, 987); +assert.sameValue(instance.toString(), "+010000-06-07T08:09:10.987", "smallest 5-digit positive year formatted as 6-digit"); + +instance = new Temporal.PlainDateTime(100000, 8, 9, 10, 9, 8, 765); +assert.sameValue(instance.toString(), "+100000-08-09T10:09:08.765", "large positive year formatted as 6-digit"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/prop-desc.js new file mode 100644 index 0000000000..cf2327d830 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype-@@tostringtag +description: The @@toStringTag property of Temporal.PlainDateTime +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.PlainDateTime.prototype, Symbol.toStringTag, { + value: "Temporal.PlainDateTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toStringTag/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/balance-negative-time-units.js new file mode 100644 index 0000000000..29ab26b63e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/balance-negative-time-units.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.plaindatetime.prototype.tozoneddatetime +description: Negative time fields are balanced upwards +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-addtime step 8: + 8. Return ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_). + sec-temporal-adddatetime step 1: + 1. Let _timeResult_ be ? AddTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). + sec-temporal-builtintimezonegetinstantfor step 13.a: + a. Let _earlier_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], 0, 0, 0, 0, 0, 0, 0, 0, 0, −_nanoseconds_, *"constrain"*). + sec-temporal.plaindatetime.prototype.tozoneddatetime step 6: + 6. Let _instant_ be BuiltinTimeZoneGetInstantFor(_timeZone_, _dateTime_, _disambiguation_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const shiftInstant = new Temporal.Instant(3661_001_001_001n); +const tz = TemporalHelpers.oneShiftTimeZone(shiftInstant, 2); +const datetime = new Temporal.PlainDateTime(1970, 1, 1, 1, 1, 1, 1, 1, 1); + +// This code path is encountered if disambiguation is `earlier` and the shift is +// a spring-forward change +datetime.toZonedDateTime(tz, { disambiguation: "earlier" }); + +const expected = [ + "1970-01-01T01:01:01.001001001", + "1970-01-01T01:01:01.001000999", +]; +assert.compareArray(tz.getPossibleInstantsForCalledWith, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/basic.js new file mode 100644 index 0000000000..9abaecb1c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Straightforward case of using UTC +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(2020, 1, 1, 0, 0); +const zdt = dt.toZonedDateTime("UTC"); + +assert.sameValue(zdt.epochNanoseconds, 1577836800000000000n, "nanoseconds"); +assert.sameValue(zdt.calendarId, "iso8601", "calendar"); +assert.sameValue(zdt.timeZoneId, "UTC", "timezone"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/branding.js new file mode 100644 index 0000000000..19ebf25c4a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toZonedDateTime = Temporal.PlainDateTime.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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => toZonedDateTime.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/builtin.js new file mode 100644 index 0000000000..0480fffbb9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.toZonedDateTime), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.toZonedDateTime), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.toZonedDateTime), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.toZonedDateTime.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguate-empty-possible-instants-with-datetime-near-limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguate-empty-possible-instants-with-datetime-near-limits.js new file mode 100644 index 0000000000..a164297267 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguate-empty-possible-instants-with-datetime-near-limits.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tozoneddatetime +description: > + Throws when at minimum resp. maximum value and possible instants is an empty List. +info: | + DisambiguatePossibleInstants ( possibleInstants, timeZone, dateTime, disambiguation ) + + ... + 9. If ! IsValidEpochNanoseconds(dayBeforeNs) is false, throw a RangeError exception. + ... + 12. If ! IsValidEpochNanoseconds(dayAfterNs) is false, throw a RangeError exception. + ... +features: [Temporal] +---*/ + +class TZ extends Temporal.TimeZone { + getPossibleInstantsFor() { + return []; + } +} + +var tz = new TZ("UTC"); +var min = new Temporal.PlainDateTime(-271821, 4, 20); +var max = new Temporal.PlainDateTime(275760, 9, 13); + +assert.throws(RangeError, () => min.toZonedDateTime(tz), "minimum date-time"); +assert.throws(RangeError, () => max.toZonedDateTime(tz), "maximum date-time"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-invalid-string.js new file mode 100644 index 0000000000..45d0f0f4c6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-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.plaindatetime.prototype.tozoneddatetime +description: RangeError thrown when disambiguation 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-totemporaldisambiguation step 1: + 1. Return ? GetOption(_normalizedOptions_, *"disambiguation"*, « String », « *"compatible"*, *"earlier"*, *"later"*, *"reject"* », *"compatible"*). + sec-temporal.plaindatetime.prototype.tozoneddatetime step 5: + 5. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2001, 9, 9, 1, 46, 40, 987, 654, 321); +const timeZone = new Temporal.TimeZone("UTC"); +const invalidStrings = ["obviously bad", "", "EARLIER", "earlıer", "late\u0131r", "reject\0"]; +invalidStrings.forEach((s) => { + assert.throws( + RangeError, + () => datetime.toZonedDateTime(timeZone, { disambiguation: s }), + `invalid disambiguation string (${s})`); +}); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-undefined.js new file mode 100644 index 0000000000..81ae9ac9f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-undefined.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tozoneddatetime +description: Fallback value for disambiguation option +info: | + sec-getoption step 3: + 3. If _value_ is *undefined*, return _fallback_. + sec-temporal-totemporaldisambiguation step 1: + 1. Return ? GetOption(_normalizedOptions_, *"disambiguation"*, « String », « *"compatible"*, *"earlier"*, *"later"*, *"reject"* », *"compatible"*). + sec-temporal.plaindatetime.prototype.tozoneddatetime step 5: + 5. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const timeZone = TemporalHelpers.springForwardFallBackTimeZone(); +const springForwardDatetime = new Temporal.PlainDateTime(2000, 4, 2, 2, 30); +const fallBackDatetime = new Temporal.PlainDateTime(2000, 10, 29, 1, 30); + +[ + [springForwardDatetime, 954671400_000_000_000n], + [fallBackDatetime, 972808200_000_000_000n], +].forEach(([datetime, expected]) => { + const explicit = datetime.toZonedDateTime(timeZone, { disambiguation: undefined }); + assert.sameValue(explicit.epochNanoseconds, expected, "default disambiguation is compatible"); + const implicit = datetime.toZonedDateTime(timeZone, {}); + assert.sameValue(implicit.epochNanoseconds, expected, "default disambiguation is compatible"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-wrong-type.js new file mode 100644 index 0000000000..8f60ebf750 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguation-wrong-type.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.plaindatetime.prototype.tozoneddatetime +description: Type conversions for disambiguation option +info: | + sec-getoption step 9.a: + a. Set _value_ to ? ToString(_value_). + sec-temporal-totemporaldisambiguation step 1: + 1. Return ? GetOption(_normalizedOptions_, *"disambiguation"*, « String », « *"compatible"*, *"earlier"*, *"later"*, *"reject"* », *"compatible"*). + sec-temporal.plaindatetime.prototype.tozoneddatetime step 5: + 5. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2001, 9, 9, 1, 46, 40, 987, 654, 321); +const timeZone = new Temporal.TimeZone("UTC"); +TemporalHelpers.checkStringOptionWrongType("disambiguation", "compatible", + (disambiguation) => datetime.toZonedDateTime(timeZone, { disambiguation }), + (result, descr) => assert.sameValue(result.epochNanoseconds, 1_000_000_000_987_654_321n, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getpossibleinstantsfor-called-with-iso8601-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getpossibleinstantsfor-called-with-iso8601-calendar.js new file mode 100644 index 0000000000..c0fa3c570d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0, 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/PlainDateTime/prototype/toZonedDateTime/invalid-instant.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/invalid-instant.js new file mode 100644 index 0000000000..db7708bac3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/invalid-instant.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.plaindatetime.prototype.tozoneddatetime +description: Convert to zoned datetime outside valid range +features: [Temporal] +---*/ + +const max = new Temporal.PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999); +const min = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1); + +assert.throws( + RangeError, + () => max.toZonedDateTime("UTC"), + "outside of Instant range (too big)" +); + +assert.throws( + RangeError, + () => min.toZonedDateTime("UTC"), + "outside of Instant range (too small)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/length.js new file mode 100644 index 0000000000..e568058c93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toZonedDateTime, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/multiple-instants.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/multiple-instants.js new file mode 100644 index 0000000000..c8ddda8755 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/multiple-instants.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.plaindatetime.prototype.tozoneddatetime +description: Checking disambiguation options for daylight savings time changes +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tz = TemporalHelpers.springForwardFallBackTimeZone(); + +const dt1 = new Temporal.PlainDateTime(2000, 4, 2, 2); + +const zdt1 = dt1.toZonedDateTime(tz); +const zdt1_compatible = dt1.toZonedDateTime(tz, { disambiguation: "compatible" }); +const zdt1_earlier = dt1.toZonedDateTime(tz, { disambiguation: "earlier" }); +const zdt1_later = dt1.toZonedDateTime(tz, { disambiguation: "later" }); + +assert.sameValue(zdt1.epochNanoseconds, 954669600000000000n, "Fall DST (no disambiguation)"); +assert.sameValue(zdt1_compatible.epochNanoseconds, 954669600000000000n, "Fall DST (disambiguation = compatible)"); +assert.sameValue(zdt1_earlier.epochNanoseconds, 954666000000000000n, "Fall DST (disambiguation = earlier)"); +assert.sameValue(zdt1_later.epochNanoseconds, 954669600000000000n, "Fall DST (disambiguation = later)"); + +assert.throws( + RangeError, + () => dt1.toZonedDateTime(tz, { disambiguation: "reject" }), + "Fall DST (disambiguation = reject)" +); + +const dt2 = new Temporal.PlainDateTime(2000, 10, 29, 1); + +const zdt2 = dt2.toZonedDateTime(tz); +const zdt2_compatible = dt2.toZonedDateTime(tz, { disambiguation: "compatible" }); +const zdt2_earlier = dt2.toZonedDateTime(tz, { disambiguation: "earlier" }); +const zdt2_later = dt2.toZonedDateTime(tz, { disambiguation: "later" }); + +assert.sameValue(zdt2.epochNanoseconds, 972806400000000000n, "Spring DST (no disambiguation)"); +assert.sameValue(zdt2_compatible.epochNanoseconds, 972806400000000000n, "Spring DST (disambiguation = compatible)"); +assert.sameValue(zdt2_earlier.epochNanoseconds, 972806400000000000n, "Spring DST (disambiguation = earlier)"); +assert.sameValue(zdt2_later.epochNanoseconds, 972810000000000000n, "Spring DST (disambiguation = later)"); + +assert.throws( + RangeError, + () => dt2.toZonedDateTime(tz, { disambiguation: "reject" }), + "Spring DST (disambiguation = reject)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/name.js new file mode 100644 index 0000000000..20ff417853 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.toZonedDateTime, "name", { + value: "toZonedDateTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/not-a-constructor.js new file mode 100644 index 0000000000..2aaece804b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.toZonedDateTime(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.toZonedDateTime), false, + "isConstructor(Temporal.PlainDateTime.prototype.toZonedDateTime)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-object.js new file mode 100644 index 0000000000..d6d317e545 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Empty or a function object may be used as options +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2); + +const result1 = instance.toZonedDateTime("UTC", {}); +assert.sameValue( + result1.epochNanoseconds, 957225600000000000n, + "options may be an empty plain object" +); + +const result2 = instance.toZonedDateTime("UTC", () => {}); +assert.sameValue( + result2.epochNanoseconds, 957225600000000000n, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-undefined.js new file mode 100644 index 0000000000..567cd149f4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-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.tozoneddatetime +includes: [temporalHelpers.js] +description: Verify that undefined options are handled correctly. +features: [BigInt, Temporal] +---*/ + +const datetimeEarlier = new Temporal.PlainDateTime(2000, 10, 29, 1, 34, 56, 987, 654, 321); +const datetimeLater = new Temporal.PlainDateTime(2000, 4, 2, 2, 34, 56, 987, 654, 321); +const timeZone = TemporalHelpers.springForwardFallBackTimeZone(); + +[ + [datetimeEarlier, 972808496987654321n], + [datetimeLater, 954671696987654321n], +].forEach(([datetime, expected]) => { + const explicit = datetime.toZonedDateTime(timeZone, undefined); + assert.sameValue(explicit.epochNanoseconds, expected, "default disambiguation is compatible"); + + const implicit = datetime.toZonedDateTime(timeZone); + assert.sameValue(implicit.epochNanoseconds, expected, "default disambiguation is compatible"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/options-wrong-type.js new file mode 100644 index 0000000000..255c024a64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.prototype.tozoneddatetime +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.toZonedDateTime("UTC", value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/order-of-operations.js new file mode 100644 index 0000000000..8b01064161 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/order-of-operations.js @@ -0,0 +1,65 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tozoneddatetime +description: Properties on an object passed to toZonedDateTime() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalTimeZoneSlotValue + "has timeZone.getOffsetNanosecondsFor", + "has timeZone.getPossibleInstantsFor", + "has timeZone.id", + // ToTemporalDisambiguation + "get options.disambiguation", + "get options.disambiguation.toString", + "call options.disambiguation.toString", + // lookup in PlainDateTime.p.toZonedDateTime + "get timeZone.getOffsetNanosecondsFor", + "get timeZone.getPossibleInstantsFor", + // GetInstantFor + "call timeZone.getPossibleInstantsFor", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const fallBackInstance = new Temporal.PlainDateTime(2000, 10, 29, 1, 30, 0, 0, 0, 0, calendar); +const springForwardInstance = new Temporal.PlainDateTime(2000, 4, 2, 2, 30, 0, 0, 0, 0, calendar); +// clear observable operations that occurred during the constructor calls +actual.splice(0); + +const dstTimeZone = TemporalHelpers.springForwardFallBackTimeZone(); +const timeZone = TemporalHelpers.timeZoneObserver(actual, "timeZone", { + getOffsetNanosecondsFor: dstTimeZone.getOffsetNanosecondsFor, + getPossibleInstantsFor: dstTimeZone.getPossibleInstantsFor, +}); + +const options = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "compatible" }, "options"); + +instance.toZonedDateTime(timeZone, options); +assert.compareArray(actual, expected, "order of operations at normal wall-clock time"); +actual.splice(0); // clear + +fallBackInstance.toZonedDateTime(timeZone, options); +assert.compareArray(actual, expected, "order of operations at repeated wall-clock time"); +actual.splice(0); // clear + +springForwardInstance.toZonedDateTime(timeZone, options); +assert.compareArray(actual, expected.concat([ + "call timeZone.getOffsetNanosecondsFor", + "call timeZone.getOffsetNanosecondsFor", + "call timeZone.getPossibleInstantsFor", +]), "order of operations at skipped wall-clock time"); +actual.splice(0); // clear + +const rejectOptions = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "reject" }, "options"); +assert.throws(RangeError, () => springForwardInstance.toZonedDateTime(timeZone, rejectOptions)); +assert.compareArray(actual, expected, "order of operations at skipped wall-clock time with disambiguation: reject"); +actual.splice(0); // clear + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-custom-timezone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-custom-timezone.js new file mode 100644 index 0000000000..15191200d0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-custom-timezone.js @@ -0,0 +1,52 @@ +// |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.plaindatetime.prototype.tozoneddatetime +description: TimeZone.getPossibleInstantsFor called after processing timeZone and options +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + "has timeZone.getOffsetNanosecondsFor", + "has timeZone.getPossibleInstantsFor", + "has timeZone.id", + "get options.disambiguation", + "get options.disambiguation.toString", + "call options.disambiguation.toString", + "get timeZone.getOffsetNanosecondsFor", + "get timeZone.getPossibleInstantsFor", + "call timeZone.getPossibleInstantsFor", +]; + +Object.defineProperty(Temporal.TimeZone, "from", { + get() { + actual.push("get Temporal.TimeZone.from"); + return undefined; + }, +}); + +const dateTime = Temporal.PlainDateTime.from("1975-02-02T14:25:36.123456789"); +const instant = Temporal.Instant.fromEpochNanoseconds(-205156799012345679n); + +const options = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "reject" }, "options"); + +const timeZone = TemporalHelpers.timeZoneObserver(actual, "timeZone", { + getPossibleInstantsFor(dateTimeArg) { + assert.sameValue(dateTimeArg, dateTime); + return [instant]; + }, +}); + +const result = dateTime.toZonedDateTime(timeZone, options); +assert.sameValue(result.epochNanoseconds, instant.epochNanoseconds); +assert.sameValue(result.getTimeZone(), timeZone); + +assert.compareArray(actual, expected); + +assert.sameValue(result.getISOFields().calendar, dateTime.getISOFields().calendar); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-date-time-near-limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-date-time-near-limits.js new file mode 100644 index 0000000000..75a3510938 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-date-time-near-limits.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.tozoneddatetime +description: > + Throws a RangeError if the date/time value is outside the instant limits +info: | + Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ , options ] ) + ... + 6. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone, dateTime, disambiguation). + ... +features: [Temporal] +---*/ + +// Try to create from the minimum date-time. +{ + let dt = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1); + assert.throws(RangeError, () => dt.toZonedDateTime("UTC")); +} +{ + let dt = new Temporal.PlainDateTime(-271821, 4, 19, 1, 0, 0, 0, 0, 0); + assert.throws(RangeError, () => dt.toZonedDateTime("UTC")); +} + +// Try to create from the maximum date-time. +{ + let dt = new Temporal.PlainDateTime(275760, 9, 13, 0, 0, 0, 0, 0, 1); + assert.throws(RangeError, () => dt.toZonedDateTime("UTC")); +} +{ + let dt = new Temporal.PlainDateTime(275760, 9, 13, 1, 0, 0, 0, 0, 0); + assert.throws(RangeError, () => dt.toZonedDateTime("UTC")); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/prop-desc.js new file mode 100644 index 0000000000..f485224197 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: The "toZonedDateTime" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.toZonedDateTime, + "function", + "`typeof PlainDateTime.prototype.toZonedDateTime` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "toZonedDateTime", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/toZonedDateTime/timezone-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-case-insensitive.js new file mode 100644 index 0000000000..06e6ad0128 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Time zone names are case insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..b57c3cf7f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(RangeError, () => datetime.toZonedDateTime(timeZone)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..047ccfaa4f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-not-callable.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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => datetime.toZonedDateTime(timeZone), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..17f0be600c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(RangeError, () => datetime.toZonedDateTime(timeZone)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..bcba7af74a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + timeZone.getPossibleInstantsFor = function () { + return []; + }; + assert.throws(TypeError, () => datetime.toZonedDateTime(timeZone)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js new file mode 100644 index 0000000000..a2b6ec45ac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: An iterable returned from timeZone.getPossibleInstantsFor is consumed after each call +info: | + sec-temporal.plaindatetime.prototype.tozoneddatetime step 6: + 6. 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-02T12:34:56.987654321", +]; + +TemporalHelpers.checkTimeZonePossibleInstantsIterable((timeZone) => { + const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + datetime.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 datetime = new Temporal.PlainDateTime(2030, 1, 1, 0, 30); + datetime.toZonedDateTime(timeZone); +}, expected2); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-datetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-datetime.js new file mode 100644 index 0000000000..c4e5a05eec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Conversion of ISO date-time strings to Temporal.TimeZone instances +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-string-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-leap-second.js new file mode 100644 index 0000000000..82b361d540 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Leap second is a valid ISO string for TimeZone +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-string-multiple-offsets.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-multiple-offsets.js new file mode 100644 index 0000000000..a31838d6a0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.tozoneddatetime +description: Time zone parsing from ISO strings uses the bracketed offset, not the ISO string offset +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-string-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-year-zero.js new file mode 100644 index 0000000000..0861ca32a0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string.js new file mode 100644 index 0000000000..52ed9f56d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(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/PlainDateTime/prototype/toZonedDateTime/timezone-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-wrong-type.js new file mode 100644 index 0000000000..80f945b8bb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(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/PlainDateTime/prototype/until/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..3cb35dfea1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const arg = { year: 2000, month: 5, day: 2, hour: 21, minute: 43, second: 5, calendar: "iso8601" }; +instance.until(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-number.js new file mode 100644 index 0000000000..bed336d5b5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: A number cannot be used in place of a Temporal.PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.until(arg), + `A number (${arg}) is not a valid ISO string for PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-object.js new file mode 100644 index 0000000000..6f71ba66ad --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-object.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.plaindatetime.prototype.until +description: Plain objects are accepted as an argument +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertDuration( + dt.until({ year: 2019, month: 10, day: 29, hour: 10 }), + 0, 0, 0, 15684, 18, 36, 29, 876, 543, 211, + "casts argument (plain object)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-plaindate.js new file mode 100644 index 0000000000..3a9f46bbd6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-plaindate.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.plaindatetime.prototype.until +description: Fast path for converting Temporal.PlainDate to Temporal.PlainDateTime by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.b: + b. If _item_ has an [[InitializedTemporalDate]] internal slot, then + i. Return ? CreateTemporalDateTime(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], 0, 0, 0, 0, 0, 0, _item_.[[Calendar]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalPlainDateTimeFastPath((date, calendar) => { + const datetime = new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 987, 654, 321, calendar); + const result = datetime.until(date); + assert.sameValue(result.total({ unit: "nanoseconds" }), -987654321, "PlainDate is converted to midnight"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..fd713acf45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/until/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..7ecf13b3a7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(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/PlainDateTime/prototype/until/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..cf43c5a168 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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/PlainDateTime/prototype/until/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..a9879a2e99 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(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/PlainDateTime/prototype/until/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..d3d8cb74f4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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/PlainDateTime/prototype/until/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..099de48b51 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/until/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..e65aab926c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-calendar-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[u-ca=iso8601]", "without time zone"], + ["1976-11-18T15:23[UTC][u-ca=iso8601]", "with time zone"], + ["1976-11-18T15:23[!u-ca=iso8601]", "with ! and no time zone"], + ["1976-11-18T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"], + ["1976-11-18T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/until/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..16d8c27c45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-critical-unknown-annotation.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar]", + "1970-01-01T00:00[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/until/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..eb9a8f4dd4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +const validStrings = [ + "1976-11-18T15:23+00:00", + "1976-11-18T15:23+00:00[UTC]", + "1976-11-18T15:23+00:00[!UTC]", + "1976-11-18T15:23-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 PlainDateTime` + ); +} + +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 PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..6c373cfff4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/until/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..3d9b9e28f5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-multiple-time-zone.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00[UTC][UTC]", + "1970-01-01T00:00[!UTC][UTC]", + "1970-01-01T00:00[UTC][!UTC]", + "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/until/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-time-separators.js new file mode 100644 index 0000000000..320238e6a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23", "uppercase T"], + ["1976-11-18t15:23", "lowercase T"], + ["1976-11-18 15:23", "space between date and time"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/until/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..f20fd0bdcd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-time-zone-annotation.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[Asia/Kolkata]", "named, with no offset"], + ["1976-11-18T15:23[!Europe/Vienna]", "named, with ! and no offset"], + ["1976-11-18T15:23[+00:00]", "numeric, with no offset"], + ["1976-11-18T15:23[!-02:30]", "numeric, with ! and no offset"], + ["1976-11-18T15:23+00:00[UTC]", "named, with offset"], + ["1976-11-18T15:23+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1976-11-18T15:23+00:00[+01:00]", "numeric, with offset"], + ["1976-11-18T15:23+00:00[!-08:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/until/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..a438aec643 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-unknown-annotation.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1976-11-18T15:23[foo=bar]", "alone"], + ["1976-11-18T15:23[UTC][foo=bar]", "with time zone"], + ["1976-11-18T15:23[u-ca=iso8601][foo=bar]", "with calendar"], + ["1976-11-18T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1976-11-18T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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/PlainDateTime/prototype/until/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..97129a5ba3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: RangeError thrown if a string with UTC designator is used as a PlainDateTime +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "2019-10-01T09:00:00Z", + "2019-10-01T09:00:00Z[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.until(arg), + "String with UTC designator should not be valid as a PlainDateTime" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-string.js new file mode 100644 index 0000000000..714f69d177 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-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.plaindatetime.prototype.until +description: Date-like strings are accepted +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertDuration( + dt.until("2019-10-29T10:46:38.271986102"), + 0, 0, 0, 15684, 19, 23, 8, 148, 529, 313, + "casts argument (string)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-wrong-type.js new file mode 100644 index 0000000000..58247233eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or property bag for PlainDateTime +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.PlainDateTime, "Temporal.PlainDateTime, object"], + [Temporal.PlainDateTime.prototype, "Temporal.PlainDateTime.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/PlainDateTime/prototype/until/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..29b515f78c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-balance-negative-time-units.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: 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-totemporaldatetime step 3.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + ... + ii. 1. Return ? BuiltinTimeZoneGetPlainDateTimeFor(_item_.[[TimeZone]], _instant_, _item_.[[Calendar]]). + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ ? ToTemporalDateTime(_other_). +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 diff = new Temporal.PlainDateTime(1970, 1, 1).until(datetime); + +TemporalHelpers.assertDuration(diff, 0, 0, 0, 0, 1, 1, 1, 1, 0, 999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..9f2b2bcea0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/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.plaindatetime.prototype.until +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.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +const result = instance.until(datetime); +TemporalHelpers.assertDuration(result, 0, 0, 0, -11239, -22, -40, -10, -987, -654, -320); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..99535f976c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.until(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..0455bd5317 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => plain.until(zoned), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..459ee0a25d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.until(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..5d5a71b0da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => plain.until(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-duration.js new file mode 100644 index 0000000000..9b3abb95dc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-duration.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.plaindatetime.prototype.until +description: Negative durations are balanced correctly by the modulo operation in NanosecondsToDays +info: | + sec-temporal-nanosecondstodays step 6: + 6. If Type(_relativeTo_) is not Object or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot, then + a. Return the new Record { ..., [[Nanoseconds]]: abs(_nanoseconds_) modulo _dayLengthNs_ × _sign_, ... }. + sec-temporal-balanceduration step 4: + 4. If _largestUnit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*, then + a. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _relativeTo_). + sec-temporal-differenceisodatetime steps 7 and 13: + 7. If _timeSign_ is -_dateSign_, then + ... + b. Set _timeDifference_ to ? BalanceDuration(-_timeSign_, _timeDifference_.[[Hours]], _timeDifference_.[[Minutes]], _timeDifference_.[[Seconds]], _timeDifference_.[[Milliseconds]], _timeDifference_.[[Microseconds]], _timeDifference_.[[Nanoseconds]], _largestUnit_). + ... + 13. Return ? BalanceDuration(_dateDifference_.[[Years]], _dateDifference_.[[Months]], _dateDifference_.[[Weeks]], _dateDifference_.[[Days]], _timeDifference_.[[Hours]], _timeDifference_.[[Minutes]], _timeDifference_.[[Seconds]], _timeDifference_.[[Milliseconds]], _timeDifference_.[[Microseconds]], _timeDifference_.[[Nanoseconds]], _largestUnit_). + sec-temporal.plaindatetime.prototype.until step 13: + 13. Let _diff_ be ? DifferenceISODateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier1 = new Temporal.PlainDateTime(2000, 5, 2, 9); +const later1 = new Temporal.PlainDateTime(2000, 5, 5, 10); +const result1 = later1.until(earlier1, { largestUnit: "day" }); +TemporalHelpers.assertDuration(result1, 0, 0, 0, -3, -1, 0, 0, 0, 0, 0, "date sign == time sign"); + +const earlier2 = new Temporal.PlainDateTime(2000, 5, 2, 10); +const later2 = new Temporal.PlainDateTime(2000, 5, 5, 9); +const result2 = later2.until(earlier2, { largestUnit: "day" }); +TemporalHelpers.assertDuration(result2, 0, 0, 0, -2, -23, 0, 0, 0, 0, 0, "date sign != time sign"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-time-units.js new file mode 100644 index 0000000000..82cd4276bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance-negative-time-units.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.plaindatetime.prototype.until +description: Negative time fields are balanced upwards +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-differencetime step 8: + 8. Let _bt_ be ? BalanceTime(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_). + sec-temporal-differenceisodatetime step 2: + 2. Let _timeDifference_ be ? DifferenceTime(_h1_, _min1_, _s1_, _ms1_, _mus1_, _ns1_, _h2_, _min2_, _s2_, _ms2_, _mus2_, _ns2_). + sec-temporal.plaindatetime.prototype.until step 13: + 13. Let _diff_ be ? DifferenceISODateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1996, 5, 2, 1, 1, 1, 1, 1, 1); + +const result1 = new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 0, 0, 2).until(datetime); +TemporalHelpers.assertDuration(result1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 999, "nanoseconds balance"); + +const result2 = new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 0, 2).until(datetime); +TemporalHelpers.assertDuration(result2, 0, 0, 0, 0, 1, 1, 1, 0, 999, 1, "microseconds balance"); + +const result3 = new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 0, 2).until(datetime); +TemporalHelpers.assertDuration(result3, 0, 0, 0, 0, 1, 1, 0, 999, 1, 1, "milliseconds balance"); + +const result4 = new Temporal.PlainDateTime(1996, 5, 2, 0, 0, 2).until(datetime); +TemporalHelpers.assertDuration(result4, 0, 0, 0, 0, 1, 0, 59, 1, 1, 1, "seconds balance"); + +const result5 = new Temporal.PlainDateTime(1996, 5, 2, 0, 2).until(datetime); +TemporalHelpers.assertDuration(result5, 0, 0, 0, 0, 0, 59, 1, 1, 1, 1, "minutes balance"); + +// This one is different because hours are later balanced again in BalanceDuration +const result6 = new Temporal.PlainDateTime(1996, 5, 2, 2).until(datetime); +TemporalHelpers.assertDuration(result6, 0, 0, 0, 0, 0, -58, -58, -998, -998, -999, "hours balance"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance.js new file mode 100644 index 0000000000..1950557975 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/balance.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.plaindatetime.prototype.until +description: Results with opposite-sign components (e.g. months=1, hours=-1) are balanced correctly +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const a = Temporal.PlainDateTime.from("2017-10-05T08:07:14+00:00[UTC]"); +const b = Temporal.PlainDateTime.from("2021-03-05T03:32:45+00:00[UTC]"); +const c = Temporal.PlainDateTime.from("2021-03-05T09:32:45+00:00[UTC]"); + +const r1 = a.until(b, { largestUnit: "months" }); +TemporalHelpers.assertDuration(r1, 0, 40, 0, 27, 19, 25, 31, 0, 0, 0, "r1"); +assert.sameValue(a.add(r1).toString(), b.toString(), "a.add(r1)"); + +const r2 = b.until(a, { largestUnit: "months" }); +TemporalHelpers.assertDuration(r2, 0, -40, 0, -30, -19, -25, -31, 0, 0, 0, "r2"); +assert.sameValue(b.add(r2).toString(), a.toString(), "b.add(r2)"); + +const r3 = c.until(a, { largestUnit: "months" }); +TemporalHelpers.assertDuration(r3, 0, -41, 0, 0, -1, -25, -31, 0, 0, 0, "r3"); +assert.sameValue(c.add(r3).toString(), a.toString(), "c.add(r3)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/branding.js new file mode 100644 index 0000000000..72c29bc1d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const until = Temporal.PlainDateTime.prototype.until; + +assert.sameValue(typeof until, "function"); + +const args = [new Temporal.PlainDateTime(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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => until.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..d36ba8a1cd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.until(new Temporal.PlainDateTime(2001, 6, 13)); + +Object.defineProperty(Temporal.Calendar.prototype, "dateUntil", dateUntilOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/builtin.js new file mode 100644 index 0000000000..8db60e1aab --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.until), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.until), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.until), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.until.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateadd-called-with-plaindate-instance.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateadd-called-with-plaindate-instance.js new file mode 100644 index 0000000000..11882b5dca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateadd-called-with-plaindate-instance.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, calendar); +instance.until(new Temporal.PlainDateTime(2000, 5, 2, 0, 0, 0, 0, 0, 0, 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/PlainDateTime/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..0614563612 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-datefromfields-called-with-null-prototype-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/until/calendar-dateuntil-called-with-copy-of-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-copy-of-options.js new file mode 100644 index 0000000000..2bf2e54661 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-copy-of-options.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: The dateUntil() method on the calendar is called with a copy of the options bag +features: [Temporal] +---*/ + +const originalOptions = { + largestUnit: "year", + shouldBeCopied: {}, +}; +let called = false; + +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + + dateUntil(d1, d2, options) { + called = true; + assert.notSameValue(options, originalOptions, "options bag should be a copy"); + assert.sameValue(options.shouldBeCopied, originalOptions.shouldBeCopied, "options bag should be a shallow copy"); + return new Temporal.Duration(); + } +} +const calendar = new Calendar(); +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); +earlier.until(later, originalOptions); +assert(called, "calendar.dateUntil must be called"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js new file mode 100644 index 0000000000..c57b59dcdb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const argument = new Temporal.PlainDateTime(2022, 6, 14, 18, 21, 36, 660, 690, 387, 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/PlainDateTime/prototype/until/calendar-dateuntil-called-with-plaindate-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-plaindate-calendar.js new file mode 100644 index 0000000000..cba7264915 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-plaindate-calendar.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.plaindatetime.prototype.until +description: calendar.dateUntil() is passed PlainDate objects with the receiver's calendar +info: | + DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit [ , options ] ) + + 8. Let _date1_ be ? CreateTemporalDate(_balanceResult_.[[Year]], _balanceResult_.[[Month]], _balanceResult_.[[Day]], _calendar_). + 9. Let _date2_ be ? CreateTemporalDate(_y2_, _mon2_, _d2_, _calendar_). + 12. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _date1_, _date2_, _untilOptions_). +features: [Temporal] +---*/ + +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + + dateUntil(d1, d2) { + assert.sameValue(d1.getCalendar(), this, "d1.calendar"); + assert.sameValue(d2.getCalendar(), this, "d2.calendar"); + return new Temporal.Duration(); + } +} +const calendar = new Calendar(); +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); +const result = earlier.until(later); +assert(result instanceof Temporal.Duration, "result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js new file mode 100644 index 0000000000..6659a56d21 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js @@ -0,0 +1,39 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: The options object passed to calendar.dateUntil has a largestUnit property with its value in the singular form +info: | + sec-temporal.plaindatetime.prototype.until step 13: + 13. Let _diff_ be ? DifferenceISODateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _other_.[[ISOYear]], _other_.[[ISOMonth]], _other_.[[ISODay]], _other_.[[ISOHour]], _other_.[[ISOMinute]], _other_.[[ISOSecond]], _other_.[[ISOMillisecond]], _other_.[[ISOMicrosecond]], _other_.[[ISONanosecond]], _dateTime_.[[Calendar]], _largestUnit_, _options_). + sec-temporal-differenceisodatetime steps 9–11: + 9. Let _dateLargestUnit_ be ! LargerOfTwoTemporalUnits(*"day"*, _largestUnit_). + 10. Let _untilOptions_ be ? MergeLargestUnitOption(_options_, _dateLargestUnit_). + 11. Let _dateDifference_ be ? CalendarDateUntil(_calendar_, _date1_, _date2_, _untilOptions_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkCalendarDateUntilLargestUnitSingular( + (calendar, largestUnit) => { + const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); + const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322, calendar); + earlier.until(later, { largestUnit }); + }, + { + years: ["year"], + months: ["month"], + weeks: ["week"], + days: [], + hours: [], + minutes: [], + seconds: [], + milliseconds: [], + microseconds: [], + nanoseconds: [] + } +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-fields-iterable.js new file mode 100644 index 0000000000..1b41916350 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.c: + c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +datetime.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/PlainDateTime/prototype/until/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/calendar-temporal-object.js new file mode 100644 index 0000000000..f44a965dda --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime 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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, temporalObject); + date.until({ year: 2005, month: 6, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/casts-argument.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/casts-argument.js new file mode 100644 index 0000000000..855e0ad714 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/casts-argument.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.plaindatetime.prototype.until +description: String and object arguments get cast +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertDuration( + datetime.until({ year: 2019, month: 10, day: 29, hour: 10 }), + 0, 0, 0, 15684, 18, 36, 29, 876, 543, 211, + "plain object argument" +); + +TemporalHelpers.assertDuration( + datetime.until("2019-10-29T10:46:38.271986102"), + 0, 0, 0, 15684, 19, 23, 8, 148, 529, 313, + "string argument gets cast" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..648b1afd9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/constructor-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/different-calendars-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/different-calendars-throws.js new file mode 100644 index 0000000000..24c5e2e39b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/different-calendars-throws.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.plaindatetime.prototype.until +description: Using different calendars is not acceptable +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0); +const dt2 = new Temporal.PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0, { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "custom", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}); + +assert.throws( + RangeError, + () => dt1.until(dt2), + "cannot use until with PDTs having different calendars" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/duplicate-calendar-fields.js new file mode 100644 index 0000000000..3beced06e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/duplicate-calendar-fields.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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'], ['hour'], ['microsecond'], ['millisecond'], ['minute'], ['month'], ['monthCode'], ['nanosecond'], ['second'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar }; + const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + + assert.throws(RangeError, () => instance.until(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..70e5f82ce0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15); +const base = { year: 2000, month: 5, day: 2, hour: 15, minute: 30, second: 45, millisecond: 987, microsecond: 654, nanosecond: 321 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].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/PlainDateTime/prototype/until/inverse.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/inverse.js new file mode 100644 index 0000000000..8c77539901 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/inverse.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.plaindatetime.prototype.until +description: The since and until operations act as inverses +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const later = new Temporal.PlainDateTime(2016, 3, 3, 18); + +TemporalHelpers.assertDurationsEqual(dt.until(later), later.since(dt), "until and since act as inverses"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-invalid-string.js new file mode 100644 index 0000000000..68f7aadcdc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-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.plaindatetime.prototype.until +description: RangeError thrown when largestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string" +]; +for (const largestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { largestUnit }), + `"${largestUnit}" is not a valid value for largestUnit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-plurals-accepted.js new file mode 100644 index 0000000000..744be9778a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-plurals-accepted.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.plaindatetime.prototype.until +description: Plural units are accepted as well for the largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 12, 13, 35, 57, 988, 655, 322); +const validUnits = [ + "year", + "month", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => earlier.until(later, { largestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-smallestunit-mismatch.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-smallestunit-mismatch.js new file mode 100644 index 0000000000..a281439e64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: RangeError thrown when smallestUnit is larger than largestUnit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +const units = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]; +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/PlainDateTime/prototype/until/largestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-undefined.js new file mode 100644 index 0000000000..5d5f650430 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Fallback value for largestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); + +const explicit = earlier.until(later, { largestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 1, 1, 1, 987, 654, 321, "default largestUnit is day"); +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 1, 1, 1, 987, 654, 321, "default largestUnit is day"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/largestunit-wrong-type.js new file mode 100644 index 0000000000..a9bdaf9695 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Type conversions for largestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 987, 654, 321); +TemporalHelpers.checkStringOptionWrongType("largestUnit", "year", + (largestUnit) => earlier.until(later, { largestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 1, 1, 0, 1, 1, 1, 1, 987, 654, 321, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/leap-second.js new file mode 100644 index 0000000000..7d319f4a4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/leap-second.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Leap second is a valid ISO string for PlainDateTime +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2016, 12, 31, 23, 59, 59); + +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 PlainDateTime" +); + +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 PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/length.js new file mode 100644 index 0000000000..ae05bf5d55 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.until, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/name.js new file mode 100644 index 0000000000..c07e663445 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.until, "name", { + value: "until", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/no-unnecessary-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/no-unnecessary-units.js new file mode 100644 index 0000000000..7e311f8dca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/no-unnecessary-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.plaindatetime.prototype.until +description: Do not return Durations with unnecessary units +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const feb29 = new Temporal.PlainDateTime(2020, 2, 29, 0, 0); +const feb28 = new Temporal.PlainDateTime(2021, 2, 28, 0, 0); + +TemporalHelpers.assertDuration( + feb29.until(feb28, { largestUnit: "months" }), + 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, + "does not include higher units than necessary (largest unit = months)" +); + +TemporalHelpers.assertDuration( + feb29.until(feb28, { largestUnit: "years" }), + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "does not include higher units than necessary (largest unit = years)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/not-a-constructor.js new file mode 100644 index 0000000000..9d88cc5ceb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.until(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.until), false, + "isConstructor(Temporal.PlainDateTime.prototype.until)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-empty.js new file mode 100644 index 0000000000..05233e55f6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-empty.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.plaindatetime.prototype.until +description: Empty options are valid +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration(feb20.until(feb21, {}), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "empty options (plain object) are acceptable"); + +TemporalHelpers.assertDuration(feb20.until(feb21, () => {}), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "empty options (function object) are acceptable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-invalid.js new file mode 100644 index 0000000000..cecac27183 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-invalid.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.plaindatetime.prototype.until +description: A variety of invalid option arguments +features: [Temporal, Symbol] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +const badOptions = [null, 1, 'obviously invalid', true, Symbol('foo'), 1n]; +badOptions.forEach((bad) => { + assert.throws( + TypeError, + () => feb20.until(feb21, bad), + `unacceptable options (${typeof bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-undefined.js new file mode 100644 index 0000000000..df89d800c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2000, 6, 12, 12, 34, 56, 987, 654, 322); + +const explicit = earlier.until(later, undefined); +assert.sameValue(explicit.years, 0, "default largest unit is days"); +assert.sameValue(explicit.months, 0, "default largest unit is days"); +assert.sameValue(explicit.weeks, 0, "default largest unit is days"); +assert.sameValue(explicit.days, 41, "default largest unit is days"); +assert.sameValue(explicit.nanoseconds, 1, "default smallest unit is nanoseconds and no rounding"); + +const implicit = earlier.until(later); +assert.sameValue(implicit.years, 0, "default largest unit is days"); +assert.sameValue(implicit.months, 0, "default largest unit is days"); +assert.sameValue(implicit.weeks, 0, "default largest unit is days"); +assert.sameValue(implicit.days, 41, "default largest unit is days"); +assert.sameValue(implicit.nanoseconds, 1, "default smallest unit is nanoseconds and no rounding"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/options-wrong-type.js new file mode 100644 index 0000000000..f5098cf0eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.until(new Temporal.PlainDateTime(1976, 11, 18), value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js new file mode 100644 index 0000000000..0cc2af79e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js @@ -0,0 +1,250 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDateTime + "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.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.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.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 6, + monthCode: "M06", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", 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(otherDateTimePropertyBag, 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, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +instance.until(identicalPropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations with identical datetimes"); +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(otherDateTimePropertyBag, 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, + hour: 12, + minute: 34, + second: 56, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + 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.dateUntil", // 13.m + "call this.calendar.dateAdd", // 13.w MoveRelativeDate + // BalanceDateDurationRelative + "call this.calendar.dateAdd", // 10.d + "call this.calendar.dateUntil" // 10.e +]); +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = years"); +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(otherDateTimePropertyBag, 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/PlainDateTime/prototype/until/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/prop-desc.js new file mode 100644 index 0000000000..4b537789d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: The "until" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.until, + "function", + "`typeof PlainDateTime.prototype.until` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "until", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/proto-in-calendar-fields.js new file mode 100644 index 0000000000..dd01f8a68b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/proto-in-calendar-fields.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.until(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..8b50fbddf6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/read-time-fields-before-datefromfields.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.plaindatetime.prototype.until +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.plaindatetime.prototype.until step 3: + 3. Set _other_ to ? ToTemporalDateTime(_other_). + sec-temporal-totemporaldatetime step 2.e: + e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + sec-temporal-interprettemporaldatetimefields steps 1–2: + 1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_). + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321); +const duration = datetime.until({ year: 2021, month: 3, day: 31, calendar }); + +TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, -12, -34, -56, -987, -654, -321); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/returns-days.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/returns-days.js new file mode 100644 index 0000000000..f43542929b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/returns-days.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.plaindatetime.prototype.until +description: Return days by default +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "auto" }), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "defaults to returning days (largest unit = auto)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "days" }), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, + "defaults to returning days (largest unit = days)" +); + +TemporalHelpers.assertDuration( + feb20.until(new Temporal.PlainDateTime(2021, 2, 1, 0, 0, 0, 0, 0, 1)), + 0, 0, 0, 366, 0, 0, 0, 0, 0, 1, + "returns nanoseconds if argument is PDT with non-zero nanoseconds" +); + +const dt = new Temporal.PlainDateTime(2020, 2, 1, 0, 0, 0, 0, 0, 1); + +TemporalHelpers.assertDuration( + dt.until(feb21), + 0, 0, 0, 365, 23, 59, 59, 999, 999, 999, + "one nanosecond away from one year away" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-cross-unit-boundary.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-cross-unit-boundary.js new file mode 100644 index 0000000000..4a687a2d70 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-cross-unit-boundary.js @@ -0,0 +1,36 @@ +// |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.plaindatetime.prototype.until +description: Rounding can cross unit boundaries up to largestUnit +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +// Date units +{ + const earlier = new Temporal.PlainDateTime(2022, 1, 1); + const later = new Temporal.PlainDateTime(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"); +} + +// Time units +{ + const earlier = new Temporal.PlainDateTime(2000, 5, 2); + const later = new Temporal.PlainDateTime(2000, 5, 2, 1, 59, 59); + const duration = earlier.until(later, { largestUnit: "hours", smallestUnit: "minutes", roundingMode: "expand" }); + TemporalHelpers.assertDuration(duration, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, "1:59 balances to 2 hours"); +} + +// Both +{ + const earlier = new Temporal.PlainDateTime(1970, 1, 1); + const later = new Temporal.PlainDateTime(1971, 12, 31, 23, 59, 59, 999, 999, 999); + const duration = earlier.until(later, { largestUnit: "years", smallestUnit: "microseconds", roundingMode: "expand" }); + TemporalHelpers.assertDuration(duration, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, "rounding up 1 ns balances to 2 years"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-negative-duration.js new file mode 100644 index 0000000000..16bd2b8838 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-negative-duration.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.plaindatetime.prototype.until +description: Negative durations are rounded correctly by the modulo operation in NanosecondsToDays +info: | + sec-temporal-nanosecondstodays step 6: + 6. If Type(_relativeTo_) is not Object or _relativeTo_ does not have an [[InitializedTemporalZonedDateTime]] internal slot, then + a. Return the new Record { ..., [[Nanoseconds]]: abs(_nanoseconds_) modulo _dayLengthNs_ × _sign_, ... }. + sec-temporal-roundduration step 6: + 6. If _unit_ is one of *"year"*, *"month"*, *"week"*, or *"day"*, then + ... + d. Let _result_ be ? NanosecondsToDays(_nanoseconds_, _intermediate_). + sec-temporal.plaindatetime.prototype.until step 14: + 14. Let _roundResult_ be ? RoundDuration(_diff_.[[Years]], _diff_.[[Months]], _diff_.[[Weeks]], _diff_.[[Days]], _diff_.[[Hours]], _diff_.[[Minutes]], _diff_.[[Seconds]], _diff_.[[Milliseconds]], _diff_.[[Microseconds]], _diff_.[[Nanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _dateTime_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12); +const later = new Temporal.PlainDateTime(2000, 5, 5); +const result = later.until(earlier, { smallestUnit: "day", roundingIncrement: 2 }); +TemporalHelpers.assertDuration(result, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-relative-to-receiver.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-relative-to-receiver.js new file mode 100644 index 0000000000..413112eab3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/round-relative-to-receiver.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.plaindatetime.prototype.until +description: Rounding happens relative to receiver +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(2019, 1, 1); +const dt2 = new Temporal.PlainDateTime(2020, 7, 2); +const options = { smallestUnit: "years", roundingMode: "halfExpand" }; + +TemporalHelpers.assertDuration( + dt1.until(dt2, options), + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "rounds relative to the receiver (positive case)" +); + +TemporalHelpers.assertDuration( + dt2.until(dt1, options), + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "rounds relative to the receiver (negative case)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/rounding-zero-year-month-week-length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/rounding-zero-year-month-week-length.js new file mode 100644 index 0000000000..893e50889c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 dt1 = new Temporal.PlainDateTime(1970, 1, 1, 0, 0, 0, 0, 0, 0, cal); +const dt2 = new Temporal.PlainDateTime(1971, 1, 1, 0, 0, 0, 0, 0, 1, cal); + +assert.throws(RangeError, () => dt1.until(dt2, { smallestUnit: "years" }), "zero year length handled correctly"); +assert.throws(RangeError, () => dt1.until(dt2, { smallestUnit: "months" }), "zero month length handled correctly"); +assert.throws(RangeError, () => dt1.until(dt2, { smallestUnit: "weeks" }), "zero week length handled correctly"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-basic.js new file mode 100644 index 0000000000..3196277706 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-basic.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.plaindatetime.prototype.until +description: A variety of rounding increments +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "hours", roundingIncrement: 3, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 3, 0, 0, 0, 0, 0, + "rounds to an increment of hours" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "minutes", roundingIncrement: 30, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 4, 30, 0, 0, 0, 0, + "rounds to an increment of minutes" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "seconds", roundingIncrement: 15, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 4, 17, 0, 0, 0, 0, + "rounds to an increment of seconds" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "milliseconds", roundingIncrement: 10, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 4, 17, 4, 860, 0, 0, + "rounds to an increment of milliseconds" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "microseconds", roundingIncrement: 10, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 4, 17, 4, 864, 200, 0, + "rounds to an increment of microseconds" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "nanoseconds", roundingIncrement: 10, roundingMode: "halfExpand"}), + 0, 0, 0, 973, 4, 17, 4, 864, 197, 530, + "rounds to an increment of nanoseconds" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-cleanly-divides.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-cleanly-divides.js new file mode 100644 index 0000000000..d9ee3df308 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-cleanly-divides.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.plaindatetime.prototype.until +description: Rounding increments that cleanly divide relevant units +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +[1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { + const options = {smallestUnit: "hours", roundingIncrement}; + assert( + earlier.until(later, options) instanceof Temporal.Duration, + `valid hour increments divide 24 (rounding increment = ${roundingIncrement})` + ); +}); + +["minutes", "seconds"].forEach((smallestUnit) => { + [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { + const options = {smallestUnit, roundingIncrement}; + assert( + earlier.until(later, options) instanceof Temporal.Duration, + `valid ${smallestUnit} increments divide 60 (rounding increment = ${roundingIncrement})` + ); + }); +}); + +["milliseconds", "microseconds", "nanoseconds"].forEach((smallestUnit) => { + [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { + const options = {smallestUnit, roundingIncrement}; + assert( + earlier.until(later, options) instanceof Temporal.Duration, + `valid ${smallestUnit} increments divide 1000 (rounding increment = ${roundingIncrement}` + ); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-does-not-divide.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-does-not-divide.js new file mode 100644 index 0000000000..92c300c98d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-does-not-divide.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.plaindatetime.prototype.until +description: Rounding increments that do not cleanly divide the relevant unit +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +const nondivisibleUnits = { + "hours": 11, + "minutes": 29, + "seconds": 29, + "milliseconds": 29, + "microseconds": 29, + "nanoseconds": 29 +}; + +Object.entries(nondivisibleUnits).forEach(([unit, increment]) => { + assert.throws( + RangeError, + () => earlier.until(later, {smallestUnit: unit, roundingIncrement: increment}), + `throws on increments that do not divide evenly into the next highest (unit = ${unit}, increment = ${increment})` + ); +}); + +const equalDivisibleUnits = { + "hours": 24, + "minutes": 60, + "seconds": 60, + "milliseconds": 1000, + "microseconds": 1000, + "nanoseconds": 1000 +}; + +Object.entries(equalDivisibleUnits).forEach(([unit, increment]) => { + assert.throws( + RangeError, + () => earlier.until(later, {smallestUnit: unit, roundingIncrement: increment}), + `throws on increments that are equal to the next highest (unit = ${unit}, rounding increment = ${increment})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-nan.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-nan.js new file mode 100644 index 0000000000..80f4f779a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); +assert.throws(RangeError, () => earlier.until(later, { roundingIncrement: NaN })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-non-integer.js new file mode 100644 index 0000000000..859509878a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +const result = earlier.until(later, { roundingIncrement: 2.5, roundingMode: "trunc" }); +TemporalHelpers.assertDuration(result, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, "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/PlainDateTime/prototype/until/roundingincrement-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-out-of-range.js new file mode 100644 index 0000000000..8b5bf55cda --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 5); +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/PlainDateTime/prototype/until/roundingincrement-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-undefined.js new file mode 100644 index 0000000000..a93a4e6b36 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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.plaindatetime.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); + +const explicit = earlier.until(later, { roundingIncrement: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, "default roundingIncrement is 1"); + +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, "default roundingIncrement is 1"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-wrong-type.js new file mode 100644 index 0000000000..7ac6ac6d1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.plaindatetime.prototype.until step 12: + 12. Let _roundingIncrement_ be ? ToTemporalRoundingIncrement(_options_, _maximum_, *false*). +includes: [temporalHelpers.js, compareArray.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 3, 13, 35, 57, 988, 655, 322); + +TemporalHelpers.checkRoundingIncrementOptionWrongType( + (roundingIncrement) => earlier.until(later, { roundingIncrement }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 397, 1, 1, 1, 1, 1, 1, descr), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 397, 1, 1, 1, 1, 1, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-ceil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-ceil.js new file mode 100644 index 0000000000..b5b23655c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-ceil.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "ceil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [3], [-2]], + ["months", [0, 32], [0, -31]], + ["weeks", [0, 0, 140], [0, 0, -139]], + ["days", [0, 0, 0, 974], [0, 0, 0, -973]], + ["hours", [0, 0, 0, 973, 5], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 18], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -4]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 865], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-expand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-expand.js new file mode 100644 index 0000000000..63eb3bba0c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-expand.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "expand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [3], [-3]], + ["months", [0, 32], [0, -32]], + ["weeks", [0, 0, 140], [0, 0, -140]], + ["days", [0, 0, 0, 974], [0, 0, 0, -974]], + ["hours", [0, 0, 0, 973, 5], [0, 0, 0, -973, -5]], + ["minutes", [0, 0, 0, 973, 4, 18], [0, 0, 0, -973, -4, -18]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 865], [0, 0, 0, -973, -4, -17, -4, -865]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-floor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-floor.js new file mode 100644 index 0000000000..4fc41c1b12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-floor.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "floor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +const expected = [ + ["years", [2], [-3]], + ["months", [0, 31], [0, -32]], + ["weeks", [0, 0, 139], [0, 0, -140]], + ["days", [0, 0, 0, 973], [0, 0, 0, -974]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -5]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -18]], + ["seconds", [0, 0, 0, 973, 4, 17, 4], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -865]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfCeil.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfCeil.js new file mode 100644 index 0000000000..c9e6d10c97 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfCeil.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "halfCeil". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfEven.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfEven.js new file mode 100644 index 0000000000..b8c1b5ee20 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfEven.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "halfEven". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfExpand.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfExpand.js new file mode 100644 index 0000000000..1a833d6d0f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfExpand.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "halfExpand". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 198], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfFloor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfFloor.js new file mode 100644 index 0000000000..96d4eb34e5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfFloor.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "halfFloor". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -198]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfTrunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfTrunc.js new file mode 100644 index 0000000000..52011b2f13 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfTrunc.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "halfTrunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 5], [0, 0, 0, -973, -4, -17, -5]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-halfexpand-default-changes.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfexpand-default-changes.js new file mode 100644 index 0000000000..72cde68fb8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfexpand-default-changes.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.plaindatetime.prototype.until +description: A different default for largest unit will be used if smallest unit is larger than "days" +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "years", roundingMode: "halfExpand"}), + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "assumes a different default for largestUnit if smallestUnit is larger than days (largest unit = years)" +); +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "months", roundingMode: "halfExpand"}), + 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, + "assumes a different default for largestUnit if smallestUnit is larger than days (largest unit = months)" +); +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "weeks", roundingMode: "halfExpand"}), + 0, 0, 139, 0, 0, 0, 0, 0, 0, 0, + "assumes a different default for largestUnit if smallestUnit is larger than days (largest unit = weeks)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-invalid-string.js new file mode 100644 index 0000000000..667e88aaa0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: RangeError thrown when roundingMode option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); +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/PlainDateTime/prototype/until/roundingmode-trunc-is-default.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-trunc-is-default.js new file mode 100644 index 0000000000..290e08cd04 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-trunc-is-default.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.plaindatetime.prototype.until +description: Show that truncation is the default rounding mode +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 321); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "minutes"}), + 0, 0, 0, 973, 4, 17,0, 0, 0, 0, + "trunc is the default (round up)" +); + +TemporalHelpers.assertDuration( + earlier.until(later, {smallestUnit: "seconds"}), + 0, 0, 0, 973, 4, 17, 4, 0, 0, 0, + "trunc is the default (round down)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-trunc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-trunc.js new file mode 100644 index 0000000000..6eb452ae4f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-trunc.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Tests calculations with roundingMode "trunc". +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2019, 1, 8, 8, 22, 36, 123, 456, 789); +const later = new Temporal.PlainDateTime(2021, 9, 7, 12, 39, 40, 987, 654, 289); + +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]], + ["hours", [0, 0, 0, 973, 4], [0, 0, 0, -973, -4]], + ["minutes", [0, 0, 0, 973, 4, 17], [0, 0, 0, -973, -4, -17]], + ["seconds", [0, 0, 0, 973, 4, 17, 4], [0, 0, 0, -973, -4, -17, -4]], + ["milliseconds", [0, 0, 0, 973, 4, 17, 4, 864], [0, 0, 0, -973, -4, -17, -4, -864]], + ["microseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197], [0, 0, 0, -973, -4, -17, -4, -864, -197]], + ["nanoseconds", [0, 0, 0, 973, 4, 17, 4, 864, 197, 500], [0, 0, 0, -973, -4, -17, -4, -864, -197, -500]], +]; + +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/PlainDateTime/prototype/until/roundingmode-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-undefined.js new file mode 100644 index 0000000000..3a25e93e3a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-undefined.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.until +description: Fallback value for roundingMode option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); + +const explicit1 = earlier.until(later, { smallestUnit: "microsecond", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit1, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, "default roundingMode is trunc"); +const implicit1 = earlier.until(later, { smallestUnit: "microsecond" }); +TemporalHelpers.assertDuration(implicit1, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, "default roundingMode is trunc"); + +const explicit2 = earlier.until(later, { smallestUnit: "millisecond", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit2, 0, 0, 0, 1, 1, 1, 1, 123, 0, 0, "default roundingMode is trunc"); +const implicit2 = earlier.until(later, { smallestUnit: "millisecond" }); +TemporalHelpers.assertDuration(implicit2, 0, 0, 0, 1, 1, 1, 1, 123, 0, 0, "default roundingMode is trunc"); + +const explicit3 = earlier.until(later, { smallestUnit: "second", roundingMode: undefined }); +TemporalHelpers.assertDuration(explicit3, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, "default roundingMode is trunc"); +const implicit3 = earlier.until(later, { smallestUnit: "second" }); +TemporalHelpers.assertDuration(implicit3, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, "default roundingMode is trunc"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-wrong-type.js new file mode 100644 index 0000000000..f8f12c6573 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Type conversions for roundingMode option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 123, 987, 500); +TemporalHelpers.checkStringOptionWrongType("roundingMode", "trunc", + (roundingMode) => earlier.until(later, { smallestUnit: "microsecond", roundingMode }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 1, 1, 1, 123, 987, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/until/smallestunit-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-invalid-string.js new file mode 100644 index 0000000000..93de6cef01 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-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.plaindatetime.prototype.until +description: RangeError thrown when smallestUnit option not one of the allowed string values +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); +const badValues = [ + "era", + "eraYear", + "millisecond\0", + "mill\u0131second", + "SECOND", + "eras", + "eraYears", + "milliseconds\0", + "mill\u0131seconds", + "SECONDS", + "other string", +]; +for (const smallestUnit of badValues) { + assert.throws(RangeError, () => earlier.until(later, { smallestUnit }), + `"${smallestUnit}" is not a valid value for smallest unit`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-plurals-accepted.js new file mode 100644 index 0000000000..493b52af8b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-plurals-accepted.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.plaindatetime.prototype.until +description: Plural units are accepted as well for the smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const later = new Temporal.PlainDateTime(2001, 6, 12, 13, 35, 57, 988, 655, 322); +const validUnits = [ + "year", + "month", + "week", + "day", + "hour", + "minute", + "second", + "millisecond", + "microsecond", + "nanosecond", +]; +TemporalHelpers.checkPluralUnitsAccepted((smallestUnit) => earlier.until(later, { smallestUnit }), validUnits); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-undefined.js new file mode 100644 index 0000000000..884259ff1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Fallback value for smallestUnit option +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); + +const explicit = earlier.until(later, { smallestUnit: undefined }); +TemporalHelpers.assertDuration(explicit, 0, 0, 0, 1, 1, 1, 1, 987, 654, 321, "default smallestUnit is nanosecond"); +const implicit = earlier.until(later, {}); +TemporalHelpers.assertDuration(implicit, 0, 0, 0, 1, 1, 1, 1, 987, 654, 321, "default smallestUnit is nanosecond"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/smallestunit-wrong-type.js new file mode 100644 index 0000000000..b646bd90bd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Type conversions for smallestUnit option +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const earlier = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 0, 0, 0); +const later = new Temporal.PlainDateTime(2000, 5, 3, 13, 35, 57, 987, 654, 321); +TemporalHelpers.checkStringOptionWrongType("smallestUnit", "microsecond", + (smallestUnit) => earlier.until(later, { smallestUnit }), + (result, descr) => TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 1, 1, 1, 987, 654, 0, descr), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/subseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/subseconds.js new file mode 100644 index 0000000000..1bf72b6a69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/subseconds.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.plaindatetime.prototype.until +description: Returned granularity may be finer than seconds +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2020, 2, 2, 0, 0, 0, 250, 250, 250); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "milliseconds" }), + 0, 0, 0, 0, 0, 0, 0, 86400250, 250, 250, + "can return subseconds (millisecond precision)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "microseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 86400250250, 250, + "can return subseconds (microsecond precision)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "nanoseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 86400250250250, + "can return subseconds (nanosecond precision)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.js new file mode 100644 index 0000000000..3da503c495 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/units-changed.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.plaindatetime.prototype.until +description: Largest unit is respected +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const feb20 = new Temporal.PlainDateTime(2020, 2, 1, 0, 0); +const feb21 = new Temporal.PlainDateTime(2021, 2, 1, 0, 0); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "years" }), + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (years)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "months" }), + 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (months)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "weeks" }), + 0, 0, 52, 2, 0, 0, 0, 0, 0, 0, + "can return lower or higher units (weeks)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "hours" }), + 0, 0, 0, 0, 8784, 0, 0, 0, 0, 0, + "can return lower or higher units (hours)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "minutes" }), + 0, 0, 0, 0, 0, 527040, 0, 0, 0, 0, + "can return lower or higher units (minutes)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "seconds" }), + 0, 0, 0, 0, 0, 0, 31622400, 0, 0, 0, + "can return lower or higher units (seconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "milliseconds" }), + 0, 0, 0, 0, 0, 0, 0, 31622400000, 0, 0, + "can return lower or higher units (milliseconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "microseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 31622400000000, 0, + "can return lower or higher units (microseconds)" +); + +TemporalHelpers.assertDuration( + feb20.until(feb21, { largestUnit: "nanoseconds" }), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 31622400000000000, + "can return lower or higher units (nanoseconds)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/weeks-months-mutually-exclusive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/weeks-months-mutually-exclusive.js new file mode 100644 index 0000000000..36acc146d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/weeks-months-mutually-exclusive.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.plaindatetime.prototype.until +description: Weeks and months are mutually exclusive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const laterDateTime = dt.add({ days: 42, hours: 3 }); + +TemporalHelpers.assertDuration( + dt.until(laterDateTime, { largestUnit: "weeks" }), + 0, 0, 6, 0, 3, 0, 0, 0, 0, 0, + "weeks and months mutually exclusive (prefer weeks)" +); + +TemporalHelpers.assertDuration( + dt.until(laterDateTime, { largestUnit: "months" }), + 0, 1, 0, 12, 3, 0, 0, 0, 0, 0, + "weeks and months mutually exclusive (prefer months)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/until/year-zero.js new file mode 100644 index 0000000000..cd6f5f364a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.until +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-12-07", + "-000000-12-07T03:24:30", + "-000000-12-07T03:24:30+01:00", + "-000000-12-07T03:24:30+00:00[UTC]", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +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/PlainDateTime/prototype/valueOf/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/basic.js new file mode 100644 index 0000000000..8cc67cdb3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/basic.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.valueof +description: Comparison operators (except !== and ===) do not work +features: [Temporal] +---*/ + +const dt1 = new Temporal.PlainDateTime(1963, 2, 13, 9, 36, 29, 123, 456, 789); +const dt1again = new Temporal.PlainDateTime(1963, 2, 13, 9, 36, 29, 123, 456, 789); +const dt2 = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +assert.sameValue(dt1 === dt1, true, "object equality implies ==="); +assert.sameValue(dt1 !== dt1again, true, "object non-equality, even if all data is the same, implies !=="); +assert.throws(TypeError, () => dt1 < dt1, "< throws (same objects)"); +assert.throws(TypeError, () => dt1 < dt2, "< throws (different objects)"); +assert.throws(TypeError, () => dt1 > dt1, "> throws (same objects)"); +assert.throws(TypeError, () => dt1 > dt2, "> throws (different objects)"); +assert.throws(TypeError, () => dt1 <= dt1, "<= does not throw (same objects)"); +assert.throws(TypeError, () => dt1 <= dt2, "<= throws (different objects)"); +assert.throws(TypeError, () => dt1 >= dt1, ">= throws (same objects)"); +assert.throws(TypeError, () => dt1 >= dt2, ">= throws (different objects)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/branding.js new file mode 100644 index 0000000000..7325efb87e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const valueOf = Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => valueOf.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/builtin.js new file mode 100644 index 0000000000..ebb2963ac2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.valueOf), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.valueOf), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.valueOf), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.valueOf.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/length.js new file mode 100644 index 0000000000..7c64b114ea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.valueOf, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/name.js new file mode 100644 index 0000000000..205c983cf8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.valueOf, "name", { + value: "valueOf", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/not-a-constructor.js new file mode 100644 index 0000000000..36a384a2c0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.valueOf(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.valueOf), false, + "isConstructor(Temporal.PlainDateTime.prototype.valueOf)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/prop-desc.js new file mode 100644 index 0000000000..60ad86a0d2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.valueof +description: The "valueOf" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.valueOf, + "function", + "`typeof PlainDateTime.prototype.valueOf` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "valueOf", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/valueOf/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/weekOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/basic.js new file mode 100644 index 0000000000..9b1f195177 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/basic.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-get-temporal.plaindatetime.prototype.weekofyear +description: Checking week of year for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +assert.sameValue(datetime.weekOfYear, 47, "check week of year information"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/branding.js new file mode 100644 index 0000000000..826226663e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/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.plaindatetime.prototype.weekofyear +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const weekOfYear = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => weekOfYear.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..53c69b52e1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.weekOfYear; + +Object.defineProperty(Temporal.Calendar.prototype, "weekOfYear", weekOfYearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/custom.js new file mode 100644 index 0000000000..f2f8584457 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "weekOfYear arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.weekOfYear; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/prop-desc.js new file mode 100644 index 0000000000..269a04acb9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/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.plaindatetime.prototype.weekofyear +description: The "weekOfYear" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/weekOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/weekOfYear/validate-calendar-value.js new file mode 100644 index 0000000000..d1624e1617 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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/PlainDateTime/prototype/with/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/argument-not-object.js new file mode 100644 index 0000000000..f0076b021f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/argument-not-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.plaindatetime.prototype.with +description: Non-object arguments throw. +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const args = [ + undefined, + null, + true, + "2020-01-12T10:20:30", + Symbol(), + 2020, + 2020n, +]; +for (const argument of args) { + assert.throws(TypeError, () => instance.with(argument), `Does not support ${typeof argument}`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/argument-object-insufficient-data.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/argument-object-insufficient-data.js new file mode 100644 index 0000000000..c63204f4a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/argument-object-insufficient-data.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not 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: Unrecognized properties (incl. plurals of recognized units) are ignored +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws( + TypeError, + () => instance.with({}), + "empty object not acceptable" +); + +const units = ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]; + +units.forEach((unit) => { + let plural = `${unit}s`; + let options = {}; + options[plural] = 1; + assert.throws( + TypeError, + () => instance.with(options), + `plural unit ("${plural}" vs "${unit}") is not acceptable` + ); +}); + +assert.throws( + TypeError, + () => instance.with({nonsense: true}), + "throw if no recognized properties present" +); + +TemporalHelpers.assertPlainDateTime( + instance.with({year: 1965, nonsense: true}), + 1965, 5, "M05", 2, 12, 34, 56, 987, 654, 321, + "unrecognized properties ignored & does not throw if recognized properties present)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/basic.js new file mode 100644 index 0000000000..4d8893ceb1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/basic.js @@ -0,0 +1,80 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not 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: A variety of "normal" (non-throwing, non-boundary case, non-null, etc.) arguments +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ year: 2019 }), + 2019, 11, "M11", 18, 15, 23, 30, 123, 456, 789, + "with year works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ month: 5 }), + 1976, 5, "M05", 18, 15, 23, 30, 123, 456, 789, + "with month works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ monthCode: "M05" }), + 1976, 5, "M05", 18, 15, 23, 30, 123, 456, 789, + "with month code works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ day: 5 }), + 1976, 11, "M11", 5, 15, 23, 30, 123, 456, 789, + "with day works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ hour: 5 }), + 1976, 11, "M11", 18, 5, 23, 30, 123, 456, 789, + "with hour works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ minute: 5 }), + 1976, 11, "M11", 18, 15, 5, 30, 123, 456, 789, + "with minute works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ second: 5 }), + 1976, 11, "M11", 18, 15, 23, 5, 123, 456, 789, + "with second works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ millisecond: 5 }), + 1976, 11, "M11", 18, 15, 23, 30, 5, 456, 789, + "with millisecond works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ microsecond: 5 }), + 1976, 11, "M11", 18, 15, 23, 30, 123, 5, 789, + "with microsecond works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ nanosecond: 5 }), + 1976, 11, "M11", 18, 15, 23, 30, 123, 456, 5, + "with nanosecond works" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ month: 5, second: 15 }), + 1976, 5, "M05", 18, 15, 23, 15, 123, 456, 789, + "with month and second works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/branding.js new file mode 100644 index 0000000000..e658a4109b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const with_ = Temporal.PlainDateTime.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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => with_.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..63191733a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2023, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.with({ day: 5 }); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..5b28018cf0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "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/PlainDateTime/prototype/with/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/builtin.js new file mode 100644 index 0000000000..4f4737af99 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.with), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.with), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.with), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.with.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-fields-iterable.js new file mode 100644 index 0000000000..26c0c8cc9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.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 datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +datetime.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/PlainDateTime/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-fromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..53b61f8a84 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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/PlainDateTime/prototype/with/calendar-merge-fields-returns-primitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-merge-fields-returns-primitive.js new file mode 100644 index 0000000000..805ed6e5ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321, 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/PlainDateTime/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-mergefields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..295a391ef4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, 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/PlainDateTime/prototype/with/calendar-options.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-options.js new file mode 100644 index 0000000000..55f92aa702 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-options.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.plaindatetime.prototype.with +description: > + The options argument is copied and the copy is passed to + Calendar#dateFromFields. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const options = { + extra: "property", +}; +let calledDateFromFields = 0; +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + dateFromFields(fields, optionsArg) { + ++calledDateFromFields; + assert.notSameValue(optionsArg, options, "should pass copied options object"); + assert.sameValue(optionsArg.extra, "property", "should copy all properties from options object"); + assert.sameValue(Object.getPrototypeOf(optionsArg), null, "Copy has null prototype"); + return super.dateFromFields(fields, optionsArg); + } +}; +const calendar = new Calendar(); +const plaindatetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +const result = plaindatetime.with({ year: 2005 }, options); +TemporalHelpers.assertPlainDateTime(result, 2005, 5, "M05", 2, 12, 34, 56, 987, 654, 321); +assert.sameValue(calledDateFromFields, 1, "should have called overridden dateFromFields once"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.js new file mode 100644 index 0000000000..9e5eab90fb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-temporal-object-throws.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. + +/*--- +description: Throws if a Temporal object with a calendar is supplied +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +const values = [ + Temporal.PlainDate.from("2022-04-12"), + Temporal.PlainDateTime.from("2022-04-12T15:19:45"), + Temporal.PlainMonthDay.from("04-12"), + Temporal.PlainTime.from("15:19:45"), + Temporal.PlainYearMonth.from("2022-04"), + Temporal.ZonedDateTime.from("2022-04-12T15:19:45[UTC]"), +]; + +for (const value of values) { + Object.defineProperty(value, "calendar", { + get() { throw new Test262Error("should not get calendar property") } + }); + Object.defineProperty(value, "timeZone", { + get() { throw new Test262Error("should not get timeZone property") } + }); + assert.throws( + TypeError, + () => datetime.with(value), + "throws with temporal object" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-throws.js new file mode 100644 index 0000000000..9565cb370a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/calendar-throws.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. + +/*--- +description: Throws if a calendar is supplied +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => datetime.with({ year: 2021, calendar: "iso8601" }), + "throws with calendar property" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..35f27a64bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.with({hour: 12})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/copies-merge-fields-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/copies-merge-fields-object.js new file mode 100644 index 0000000000..a60773fc91 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/copies-merge-fields-object.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: The object returned from mergeFields() is copied before being passed to dateFromFields(). +info: | + sec-temporal.plaindatetime.prototype.with steps 13–15: + 13. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialDate_). + 14. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»). + 15. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + sec-temporal-interprettemporaldatetimefields step 2: + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get day", + "get day.valueOf", + "call day.valueOf", + "get hour", + "get hour.valueOf", + "call hour.valueOf", + "get microsecond", + "get microsecond.valueOf", + "call microsecond.valueOf", + "get millisecond", + "get millisecond.valueOf", + "call millisecond.valueOf", + "get minute", + "get minute.valueOf", + "call minute.valueOf", + "get month", + "get month.valueOf", + "call month.valueOf", + "get monthCode", + "get monthCode.toString", + "call monthCode.toString", + "get nanosecond", + "get nanosecond.valueOf", + "call nanosecond.valueOf", + "get second", + "get second.valueOf", + "call second.valueOf", + "get year", + "get year.valueOf", + "call year.valueOf", +]; + +const calendar = TemporalHelpers.calendarMergeFieldsGetters(); +const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321, calendar); +datetime.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/PlainDateTime/prototype/with/copy-properties-not-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/copy-properties-not-undefined.js new file mode 100644 index 0000000000..60f627767f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 plainDateTime = new Temporal.PlainDateTime(2006, 1, 24, 11, 42, 58); + +TemporalHelpers.assertPlainDateTime(plainDateTime.with({ day: 8, hour: 10, year: undefined }), + 2006, 1, "M01", 8, 10, 42, 58, 0, 0, 0, + "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/PlainDateTime/prototype/with/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/duplicate-calendar-fields.js new file mode 100644 index 0000000000..5be05fd288 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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'], ['hour'], ['microsecond'], ['millisecond'], ['minute'], ['month'], ['nanosecond'], ['second'], ['year']]) { + const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields); + const datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + + assert.throws(RangeError, () => datetime.with({hour: 12})); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..ae7ad4a2b4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].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/PlainDateTime/prototype/with/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/length.js new file mode 100644 index 0000000000..539f00c49e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.with, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/month-and-monthcode-must-agree.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/month-and-monthcode-must-agree.js new file mode 100644 index 0000000000..f936006c14 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/month-and-monthcode-must-agree.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.plaindatetime.prototype.with +description: The month and month code should agree +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +assert.throws( + RangeError, + () => datetime.with({ month: 5, monthCode: "M06" }), + "month and monthCode must agree" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/multiple-unrecognized-properties-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/multiple-unrecognized-properties-ignored.js new file mode 100644 index 0000000000..9c9eb5c6dd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/multiple-unrecognized-properties-ignored.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. + +/*--- +description: Unrecognized units are ignored +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const units = ["year", "month", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]; + +units.forEach((unit) => { + let plural = `${unit}s`; + let arg = { month: 12 }; + arg[plural] = 1; + TemporalHelpers.assertPlainDateTime( + datetime.with(arg), + 1976, 12, "M12", 18, 15, 23, 30, 123, 456, 789, + `unrecognized property (${plural}) gets ignored` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/name.js new file mode 100644 index 0000000000..a30c3f28e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.with, "name", { + value: "with", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/not-a-constructor.js new file mode 100644 index 0000000000..3ab26bd234 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.with(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.with), false, + "isConstructor(Temporal.PlainDateTime.prototype.with)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-empty.js new file mode 100644 index 0000000000..9ac3c21267 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-empty.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.plaindatetime.prototype.with +description: Verify that undefined options are handled correctly. +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ day: 40 }, {}), + 1976, 11, "M11", 30, 15, 23, 30, 123, 456, 789, + "options may be empty object" +); + +TemporalHelpers.assertPlainDateTime( + datetime.with({ day: 40 }, () => {}), + 1976, 11, "M11", 30, 15, 23, 30, 123, 456, 789, + "read empty options from function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-invalid.js new file mode 100644 index 0000000000..2f945aeb50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-invalid.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.plaindatetime.prototype.with +description: Verify that undefined options are handled correctly. +features: [Temporal, Symbol] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +const badOptions = [null, 1, 'hello', true, Symbol('foo'), 1n]; + +badOptions.forEach((bad) => { + assert.throws( + TypeError, + () => datetime.with({ day: 5 }, bad), + `bad options (${typeof bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-undefined.js new file mode 100644 index 0000000000..0b37d9c62a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: Verify that undefined options are handled correctly. +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 2, 2, 12, 34, 56, 987, 654, 321); +const fields = { day: 31 }; + +const explicit = datetime.with(fields, undefined); +assert.sameValue(explicit.month, 2, "default overflow is constrain"); +assert.sameValue(explicit.day, 29, "default overflow is constrain"); + +const implicit = datetime.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/PlainDateTime/prototype/with/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/options-wrong-type.js new file mode 100644 index 0000000000..0831b45561 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.PlainDateTime(2000, 5, 2); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.with({ day: 5 }, value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js new file mode 100644 index 0000000000..a408ffd916 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js @@ -0,0 +1,110 @@ +// |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.plaindatetime.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.hour", + "get fields.hour.valueOf", + "call fields.hour.valueOf", + "get fields.microsecond", + "get fields.microsecond.valueOf", + "call fields.microsecond.valueOf", + "get fields.millisecond", + "get fields.millisecond.valueOf", + "call fields.millisecond.valueOf", + "get fields.minute", + "get fields.minute.valueOf", + "call fields.minute.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.nanosecond", + "get fields.nanosecond.valueOf", + "call fields.nanosecond.valueOf", + "get fields.second", + "get fields.second.valueOf", + "call fields.second.valueOf", + "get fields.year", + "get fields.year.valueOf", + "call fields.year.valueOf", + // CalendarMergeFields + "call this.calendar.mergeFields", + // InterpretTemporalDateTimeFields + "get options.overflow.toString", + "call options.overflow.toString", + "call this.calendar.dateFromFields", +]; +const actual = []; + +const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +// clear observable operations that occurred during the constructor call +actual.splice(0); + +TemporalHelpers.observeProperty(actual, instance, "hour", 12, "this"); +TemporalHelpers.observeProperty(actual, instance, "minute", 34, "this"); +TemporalHelpers.observeProperty(actual, instance, "second", 56, "this"); +TemporalHelpers.observeProperty(actual, instance, "millisecond", 987, "this"); +TemporalHelpers.observeProperty(actual, instance, "microsecond", 654, "this"); +TemporalHelpers.observeProperty(actual, instance, "nanosecond", 321, "this"); + +const fields = TemporalHelpers.propertyBagObserver(actual, { + year: 1.7, + month: 1.7, + monthCode: "M01", + day: 1.7, + hour: 1.7, + minute: 1.7, + second: 1.7, + millisecond: 1.7, + microsecond: 1.7, + nanosecond: 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/PlainDateTime/prototype/with/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-invalid-string.js new file mode 100644 index 0000000000..750d7be7e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/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.plaindatetime.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-interprettemporaldatetimefields steps 2–3: + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). + 3. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindatetime.prototype.with step 16: + 16. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); + +const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"]; +for (const overflow of badOverflows) { + assert.throws( + RangeError, + () => datetime.with({ minute: 45 }, { overflow }), + `invalid overflow ("${overflow}")` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-undefined.js new file mode 100644 index 0000000000..32cf45f248 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-undefined.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.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-interprettemporaldatetimefields steps 2–3: + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). + 3. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindatetime.prototype.with step 16: + 16. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); +const explicit = datetime.with({ minute: 67 }, { overflow: undefined }); +TemporalHelpers.assertPlainDateTime(explicit, 2000, 5, "M05", 2, 12, 59, 0, 0, 0, 0, "default overflow is constrain"); +const implicit = datetime.with({ minute: 67 }, {}); +TemporalHelpers.assertPlainDateTime(implicit, 2000, 5, "M05", 2, 12, 59, 0, 0, 0, 0, "default overflow is constrain"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-wrong-type.js new file mode 100644 index 0000000000..6af0e9768a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/overflow-wrong-type.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.plaindatetime.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-interprettemporaldatetimefields steps 2–3: + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). + 3. Let _overflow_ be ? ToTemporalOverflow(_options_). + sec-temporal.plaindatetime.prototype.with step 16: + 16. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12); + +// See TemporalHelpers.checkStringOptionWrongType(); this code path has +// different expectations for observable calls + +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: null }), "null"); +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: true }), "true"); +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: false }), "false"); +assert.throws(TypeError, () => datetime.with({ minute: 45 }, { overflow: Symbol() }), "symbol"); +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: 2 }), "number"); +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: 2n }), "bigint"); +assert.throws(RangeError, () => datetime.with({ minute: 45 }, { overflow: {} }), "plain object"); + +// toString property should only be read and converted to a string once, because +// a copied object with the resulting string on it is passed to +// Calendar.dateFromFields(). +const expected = [ + "get overflow.toString", + "call overflow.toString", +]; +const actual = []; +const observer = TemporalHelpers.toPrimitiveObserver(actual, "constrain", "overflow"); +const result = datetime.with({ minute: 45 }, { overflow: observer }); +TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 45, 0, 0, 0, 0, "object with toString"); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/prop-desc.js new file mode 100644 index 0000000000..bbbe9d6d15 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: The "with" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.with, + "function", + "`typeof PlainDateTime.prototype.with` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "with", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/proto-in-calendar-fields.js new file mode 100644 index 0000000000..6bfd62f345 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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 datetime = new Temporal.PlainDateTime(2023, 5, 1, 0, 0, 0, 0, 0, 0, calendar); + +assert.throws(RangeError, () => datetime.with({hour: 12})); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..9fc273cdfb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/read-time-fields-before-datefromfields.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.plaindatetime.prototype.with +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.plaindatetime.prototype.with step 15: + 15. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_). + sec-temporal-interprettemporaldatetimefields steps 1–2: + 1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_). + 2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_). +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321, calendar); +const newDatetime = datetime.with({ year: 2022 }); + +assert.sameValue(newDatetime.hour, 12, "hour value"); +assert.sameValue(newDatetime.minute, 34, "minute value"); +assert.sameValue(newDatetime.second, 56, "second value"); +assert.sameValue(newDatetime.millisecond, 987, "millisecond value"); +assert.sameValue(newDatetime.microsecond, 654, "microsecond value"); +assert.sameValue(newDatetime.nanosecond, 321, "nanosecond value"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/with/string-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/string-throws.js new file mode 100644 index 0000000000..f6908a4cca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/string-throws.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. + +/*--- +description: Throws if a string argument is supplied +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const baddies = ["12:00", "1995-04-07", "2019-05-17T12:34:56.007007007", "2019-05-17T12:34:56.007007007Z", "42"]; + +baddies.forEach((bad) => { + assert.throws( + TypeError, + () => instance.with(bad), + `bad argument (${bad})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/subclassing-ignored.js new file mode 100644 index 0000000000..b06990e6bd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.with +description: Objects of a subclass are never created as return values for with() +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "with", + [{ nanosecond: 1 }], + (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 1), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/timezone-throws.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/timezone-throws.js new file mode 100644 index 0000000000..3460a16758 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/with/timezone-throws.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. + +/*--- +description: Throws if a timezone is supplied +esid: sec-temporal.plaindatetime.prototype.with +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); + +assert.throws( + TypeError, + () => datetime.with({ year: 2021, timeZone: "UTC" }), + "throws with timezone property" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/argument-string.js new file mode 100644 index 0000000000..e9e1586477 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/argument-string.js @@ -0,0 +1,57 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withcalendar +description: String argument, if it names a recognizable calendar, gets cast +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const calendar = { + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + id: "something special", + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + toString() { return "something special"; }, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +const result = dt.withCalendar("iso8601"); + +TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 15, 23, 30, 123, 456, 789, + "'iso8601' is a recognizable calendar" +); + +assert.sameValue( + result.getISOFields().calendar, + "iso8601", + "underlying calendar has changed and calendar slot stores a string" +); + +assert.throws( + RangeError, + () => dt.withCalendar("this will fail"), + "unknown calendar throws" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/basic.js new file mode 100644 index 0000000000..1509be6e07 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/basic.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.plaindatetime.prototype.withcalendar +description: Non-throwing non-edge case +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); +const calendar = new Temporal.Calendar("iso8601"); + +const result = dt.withCalendar(calendar); + +TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 15, 23, 30, 123, 456, 789, + "works" +); + +assert.sameValue(result.getCalendar(), calendar, "underlying calendar is unchanged"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/branding.js new file mode 100644 index 0000000000..a888613ab4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const withCalendar = Temporal.PlainDateTime.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.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => withCalendar.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..004403b09a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.withCalendar("iso8601"); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/builtin.js new file mode 100644 index 0000000000..49f64fd2fc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: > + Tests that Temporal.PlainDateTime.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.PlainDateTime.prototype.withCalendar), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.withCalendar), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.withCalendar), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.withCalendar.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-case-insensitive.js new file mode 100644 index 0000000000..90f3905fff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: Calendar names are case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-number.js new file mode 100644 index 0000000000..34afdcd997 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: A number is not allowed to be a calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/calendar-string-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-string-leap-second.js new file mode 100644 index 0000000000..bd62a3a13c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: Leap second is a valid ISO string for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-string.js new file mode 100644 index 0000000000..c8018bde0d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-temporal-object.js new file mode 100644 index 0000000000..fdabe3e22c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/calendar-wrong-type.js new file mode 100644 index 0000000000..ff7d515fbf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, { + 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/PlainDateTime/prototype/withCalendar/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/length.js new file mode 100644 index 0000000000..73d506d949 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/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.plaindatetime.prototype.withcalendar +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.withCalendar, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/missing-argument.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/missing-argument.js new file mode 100644 index 0000000000..502f7a9f48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: TypeError thrown when calendar argument not given +features: [Temporal] +---*/ + +const plainDateTime = Temporal.PlainDateTime.from("1976-11-18T14:00:00"); +assert.throws(TypeError, () => plainDateTime.withCalendar(), "missing argument"); +assert.throws(TypeError, () => plainDateTime.withCalendar(undefined), "undefined argument"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/name.js new file mode 100644 index 0000000000..1d9d820482 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: Temporal.PlainDateTime.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.PlainDateTime.prototype.withCalendar, "name", { + value: "withCalendar", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/not-a-constructor.js new file mode 100644 index 0000000000..fd1c779874 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: > + Temporal.PlainDateTime.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.PlainDateTime.prototype.withCalendar(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.withCalendar), false, + "isConstructor(Temporal.PlainDateTime.prototype.withCalendar)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/prop-desc.js new file mode 100644 index 0000000000..9059757976 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.withcalendar +description: The "withCalendar" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.withCalendar, + "function", + "`typeof PlainDateTime.prototype.withCalendar` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "withCalendar", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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/PlainDateTime/prototype/withCalendar/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withCalendar/subclassing-ignored.js new file mode 100644 index 0000000000..f8670228b6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "withCalendar", + [customCalendar], + (result) => { + TemporalHelpers.assertPlainDateTime(result, 1900, 2, "M02", 5, 12, 34, 56, 987, 654, 321); + assert.sameValue(result.getCalendar(), customCalendar, "calendar result"); + }, +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..aff156fa39 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" }; +instance.withPlainDate(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..f070f616c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.withPlainDate(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/PlainDateTime/prototype/withPlainDate/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-constructor-in-calendar-fields.js new file mode 100644 index 0000000000..7db65ba3b4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.withPlainDate(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-duplicate-calendar-fields.js new file mode 100644 index 0000000000..094d3b1764 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + + assert.throws(RangeError, () => instance.withPlainDate(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-leap-second.js new file mode 100644 index 0000000000..cd45b2dbdf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Leap second is a valid ISO string for PlainDate +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.withPlainDate(arg); +TemporalHelpers.assertPlainDateTime( + result1, + 2016, 12, "M12", 31, 12, 34, 56, 987, 654, 321, + "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.withPlainDate(arg); +TemporalHelpers.assertPlainDateTime( + result2, + 2016, 12, "M12", 31, 12, 34, 56, 987, 654, 321, + "second: 60 is ignored in property bag for PlainDate" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-number.js new file mode 100644 index 0000000000..48bbc1cf50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: A number cannot be used in place of a Temporal.PlainDate +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.withPlainDate(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/PlainDateTime/prototype/withPlainDate/argument-object-insufficient-data.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insufficient-data.js new file mode 100644 index 0000000000..e7d7859da5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object-insufficient-data.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.plaindatetime.prototype.withplaindate +description: Unrecognized properties of plain object ignored +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30); + +assert.throws( + TypeError, + () => dt.withPlainDate({}), + "empty object not acceptable" +); + +assert.throws( + TypeError, + () => dt.withPlainDate({ months: 12 }), // should be "month" + "no recognized properties (look like it might work)" +); + +assert.throws( + TypeError, + () => dt.with({nonsense: true}), + "no recognized properties (clearly won't work)" +); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainDate({ year: 2000, month: 6, day: 1, months: 123 }), // 'months' unrecognized; see above + 2000, 6, "M06", 1, 3, 24, 30, 0, 0, 0, + "unrecognized properties ignored & does not throw if recognized properties present)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object.js new file mode 100644 index 0000000000..7e7bbddf1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-object.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.plaindatetime.prototype.withplaindate +description: Plain object may be acceptable +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainDate({ year: 2000, month: 6, day: 1 }), + 2000, 6, "M06", 1, 3, 24, 30, 0, 0, 0, + "plain object works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js new file mode 100644 index 0000000000..1255bf51c1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.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.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved with ISO PDT +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal = { + id: 'thisisnotiso', + era() { return undefined; }, + eraYear() { return undefined; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0); +assert.sameValue(pdt.calendarId, "iso8601", "PlainDateTime with ISO calendar"); +const pd = new Temporal.PlainDate(2010, 11, 12, cal); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is changed if receiver has ISO calendar (1)" + // Testing of era and eraYear should only be coded under intl402 +); + +assert.sameValue( + shifted.getCalendar(), + cal, + "calendar is changed if receiver has ISO calendar (2)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js new file mode 100644 index 0000000000..3ef31c8d45 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js @@ -0,0 +1,79 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved when both calendars have the same id +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal1 = { + id: "this is a string", + toString() { return "this is another string"; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + day() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + month() {}, + monthCode() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + year() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const cal2 = { + id: "this is a string", + era() { return undefined; }, + eraYear() { return undefined; }, + toString() { return "thisisnotiso"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal1); +const pd = new Temporal.PlainDate(2010, 11, 12, cal2); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is changed with same id (1)" + // Testing of era and eraYear should only be coded under intl402 +); + +assert.sameValue( + shifted.getCalendar(), + cal2, + "calendar is changed with same id (2)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js new file mode 100644 index 0000000000..7c36ca99e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js @@ -0,0 +1,60 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate calendar is preserved when both calendars are the same object +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +let calls = 0; +const cal = { + id: 'thisisnotiso', + era() { return undefined; }, + eraYear() { return undefined; }, + toString() { + ++calls; + return "this is a string"; + }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); +const pd = new Temporal.PlainDate(2010, 11, 12, cal); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is unchanged with same calendars (1)" + // Testing of era and eraYear should only be coded under intl402 +); + +assert.sameValue( + shifted.getCalendar(), + cal, + "calendar is unchanged with same calendars (2)" +); +assert.sameValue(calls, 0, "should not have called cal.toString()"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js new file mode 100644 index 0000000000..d85612f889 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.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.plaindatetime.prototype.withplaindate +description: Original PDT calendar is preserved with ISO PlainDate +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal = { + id: 'thisisnotiso', + era() { return undefined; }, + eraYear() { return undefined; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const pdt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); +const pd = new Temporal.PlainDate(2010, 11, 12); +assert.sameValue(pd.calendarId, "iso8601", "PlainDate with ISO calendar"); +const shifted = pdt.withPlainDate(pd); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is unchanged if input has ISO calendar (1)" + // Testing of era and eraYear should only be coded under intl402 +); + +assert.sameValue( + shifted.getCalendar(), + cal, + "calendar is unchanged if input has ISO calendar (2)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate.js new file mode 100644 index 0000000000..fb713898c1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: PlainDate object is acceptable +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30); +const date = new Temporal.PlainDate(2020, 1, 23); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainDate(date), + 2020, 1, "M01", 23, 3, 24, 30, 0, 0, 0, + "PlainDate argument works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindatetime.js new file mode 100644 index 0000000000..377c7724a0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.withplaindate +description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.withplaindate step 3: + 3. Let _plainDate_ be ? ToTemporalDate(_plainDateLike_). + 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 receiver = new Temporal.PlainDateTime(2001, 9, 9, 6, 54, 32, 123, 456, 789); + const result = receiver.withPlainDate(datetime); + TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 6, 54, 32, 123, 456, 789); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..a5d1fd08e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: The calendar name is case-insensitive +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.withPlainDate(arg); +TemporalHelpers.assertPlainDateTime(result, 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..ac91345475 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Leap second is a valid ISO string for a calendar in a property bag +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.withPlainDate(arg); +TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..cbd1950207 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.withPlainDate(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..c8a2dcbcd9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: A calendar ID is valid input for Calendar +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.withPlainDate(arg); +TemporalHelpers.assertPlainDateTime(result, 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..0baf544ed1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.withPlainDate(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.withPlainDate(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/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..d39551d616 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-proto-in-calendar-fields.js new file mode 100644 index 0000000000..8753275d77 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(RangeError, () => instance.withPlainDate(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..e15d9e970d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainDate(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 15, 23, 0, 0, 0, 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..34d98195f3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..53e460dac6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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.withPlainDate(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 15, 23, 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.withPlainDate(arg), + `"${arg}" UTC offset without time is not valid for PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-invalid.js new file mode 100644 index 0000000000..d7d5f1c03c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as a PlainDate +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00", + "2020-01-32", + "2020-02-30", + "2021-02-29", + "2020-00-01", + "2020-13-01", + "2020-01-01T", + "2020-01-01T25:00:00", + "2020-01-01T01:60:00", + "2020-01-01T01:60:61", + "2020-01-01junk", + "2020-01-01T00:00:00junk", + "2020-01-01T00:00:00+00:00junk", + "2020-01-01T00:00:00+00:00[UTC]junk", + "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk", + "02020-01-01", + "2020-001-01", + "2020-01-001", + "2020-01-01T001", + "2020-01-01T01:001", + "2020-01-01T01:01:001", + // valid, but forms not supported in Temporal: + "2020-W01-1", + "2020-001", + "+0002020-01-01", + // valid, but this calendar must not exist: + "2020-01-01[u-ca=notexist]", + // may be valid in other contexts, but insufficient information for PlainDate: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + // valid, but outside the supported range: + "-999999-01-01", + "+999999-01-01", +]; +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `"${arg}" should not be a valid ISO string for a PlainDate` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js new file mode 100644 index 0000000000..4f253733bc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js @@ -0,0 +1,54 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.withplaindate +description: Original PDT calendar is preserved with ISO string +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const cal = { + id: "thisisnotiso", + era() { return undefined; }, + eraYear() { return undefined; }, + toString() { return "this is a string"; }, + year() { return 2008; }, + month() { return 9; }, + monthCode() { return "M09"; }, + day() { return 6; }, + dateAdd() {}, + dateFromFields() {}, + dateUntil() {}, + dayOfWeek() {}, + dayOfYear() {}, + daysInMonth() {}, + daysInWeek() {}, + daysInYear() {}, + fields() {}, + inLeapYear() {}, + mergeFields() {}, + monthDayFromFields() {}, + monthsInYear() {}, + weekOfYear() {}, + yearMonthFromFields() {}, + yearOfWeek() {}, +}; +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); +const shifted = dt.withPlainDate("2010-11-12"); + +TemporalHelpers.assertPlainDateTime( + shifted, + 2008, 9, "M09", 6, 3, 24, 30, 0, 0, 0, + "calendar is unchanged if input has ISO calendar (1)" + // Testing of era and eraYear should only be coded under intl402 +); + +assert.sameValue( + shifted.getCalendar(), + cal, + "calendar is unchanged if input has ISO calendar (2)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..e864fc5bea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..28492d2479 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-time-separators.js new file mode 100644 index 0000000000..cdfb3c1f58 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainDate(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 15, 23, 0, 0, 0, 0, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..6a110024d9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainDate(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 15, 23, 0, 0, 0, 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..642a911fec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainDate(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 2000, 5, "M05", 2, 15, 23, 0, 0, 0, 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..c0a04dcdde --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(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/PlainDateTime/prototype/withPlainDate/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string.js new file mode 100644 index 0000000000..bea0f65186 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-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.plaindatetime.prototype.withplaindate +description: PlainDate-like string argument is acceptable +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainDate("2018-09-15"), + 2018, 9, "M09", 15, 3, 24, 30, 0, 0, 0, + "PlainDate-like string argument works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-wrong-type.js new file mode 100644 index 0000000000..06f30c6762 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.withPlainDate(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.withPlainDate(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/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-convert.js new file mode 100644 index 0000000000..233705b50c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +assert.throws(Test262Error, () => instance.withPlainDate(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-slots.js new file mode 100644 index 0000000000..cab1b1db13 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +instance.withPlainDate(arg); +assert.compareArray(actual, []); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..6eeedcd1b0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.withPlainDate(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..63fe5656ec --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => plain.withPlainDate(zoned), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..d18bb10db3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.withPlainDate(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..191d49e8e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => plain.withPlainDate(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/branding.js new file mode 100644 index 0000000000..754f29a7a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const withPlainDate = Temporal.PlainDateTime.prototype.withPlainDate; + +assert.sameValue(typeof withPlainDate, "function"); + +const args = [new Temporal.PlainDate(2022, 6, 22)]; + +assert.throws(TypeError, () => withPlainDate.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => withPlainDate.apply(null, args), "null"); +assert.throws(TypeError, () => withPlainDate.apply(true, args), "true"); +assert.throws(TypeError, () => withPlainDate.apply("", args), "empty string"); +assert.throws(TypeError, () => withPlainDate.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => withPlainDate.apply(1, args), "1"); +assert.throws(TypeError, () => withPlainDate.apply({}, args), "plain object"); +assert.throws(TypeError, () => withPlainDate.apply(Temporal.PlainDateTime, args), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => withPlainDate.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..5b78381f1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.withPlainDate(new Temporal.PlainDate(2001, 6, 13)); + +Object.defineProperty(Temporal.Calendar.prototype, "id", idOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/builtin.js new file mode 100644 index 0000000000..260cb95caa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: > + Tests that Temporal.PlainDateTime.prototype.withPlainDate + 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.PlainDateTime.prototype.withPlainDate), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.withPlainDate), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.withPlainDate), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.withPlainDate.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-datefromfields-called-with-options-undefined.js new file mode 100644 index 0000000000..34b0955ac4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: > + Calendar.dateFromFields method is called with undefined as the options value + when call originates internally +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions(); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); +instance.withPlainDate({ year: 2000, month: 5, day: 3, calendar }); +assert.sameValue(calendar.dateFromFieldsCallCount, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-fields-iterable.js new file mode 100644 index 0000000000..a53cf9d14c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.plaindatetime.prototype.withplaindate step 3: + 3. Let _plainDate_ be ? ToTemporalDate(_plainDateLike_). + 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 datetime = new Temporal.PlainDateTime(2000, 5, 3, 13, 3, 27, 123, 456, 789, calendar1); +const calendar2 = TemporalHelpers.calendarFieldsIterable(); +datetime.withPlainDate({ year: 2001, month: 6, day: 4, 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/PlainDateTime/prototype/withPlainDate/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-temporal-object.js new file mode 100644 index 0000000000..ecc32638c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-temporal-object.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.plaindatetime.prototype.withplaindate +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.plaindatetime.prototype.withplaindate step 3: + 3. Let _plainDate_ be ? ToTemporalDate(_plainDateLike_). + 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 datetime = new Temporal.PlainDateTime(2000, 5, 3, 13, 3, 27, 123, 456, 789); + // the PlainDate's calendar will override the PlainDateTime's ISO calendar + const result = datetime.withPlainDate({ year: 2001, month: 6, day: 4, 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/PlainDateTime/prototype/withPlainDate/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..934b4207c9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 15); +const base = { year: 2000, month: 5, day: 2 }; + +[Infinity, -Infinity].forEach((inf) => { + ["year", "month", "day"].forEach((prop) => { + assert.throws(RangeError, () => instance.withPlainDate({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.withPlainDate({ ...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/PlainDateTime/prototype/withPlainDate/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/length.js new file mode 100644 index 0000000000..72a684301c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Temporal.PlainDateTime.prototype.withPlainDate.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.PlainDateTime.prototype.withPlainDate, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/name.js new file mode 100644 index 0000000000..4e528f6cd5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Temporal.PlainDateTime.prototype.withPlainDate.name is "withPlainDate". +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.PlainDateTime.prototype.withPlainDate, "name", { + value: "withPlainDate", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/non-compatible-calendars-throw.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/non-compatible-calendars-throw.js new file mode 100644 index 0000000000..3b7f15afb4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/non-compatible-calendars-throw.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.plaindatetime.withplaindate +description: If two non-ISO calendars are involved, an error is raised +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 cal = { + id: "foo", + toString() { return "this is a string"; }, + ...calendarMethods, +}; + +const dt = new Temporal.PlainDateTime(1995, 12, 7, 3, 24, 30, 0, 0, 0, cal); + +const anotherCal = { + id: "bar", + toString() { return "this is another string"; }, + ...calendarMethods, +}; + +const date = new Temporal.PlainDate(2008, 9, 6, anotherCal); + +assert.throws( + RangeError, + () => dt.withPlainDate(date), + "throws if both `this` and `other` have a non-ISO calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/not-a-constructor.js new file mode 100644 index 0000000000..35bb31258b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: > + Temporal.PlainDateTime.prototype.withPlainDate 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.PlainDateTime.prototype.withPlainDate(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.withPlainDate), false, + "isConstructor(Temporal.PlainDateTime.prototype.withPlainDate)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/prop-desc.js new file mode 100644 index 0000000000..4da47c13b6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: The "withPlainDate" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.withPlainDate, + "function", + "`typeof PlainDateTime.prototype.withPlainDate` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "withPlainDate", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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/PlainDateTime/prototype/withPlainDate/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/subclassing-ignored.js new file mode 100644 index 0000000000..686f5b7e44 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +description: Objects of a subclass are never created as return values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "withPlainDate", + ["1999-04-27"], + (result) => TemporalHelpers.assertPlainDateTime(result, 1999, 4, "M04", 27, 12, 34, 56, 987, 654, 321), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/year-zero.js new file mode 100644 index 0000000000..7b8342376b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainDate/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.plaindatetime.prototype.withplaindate +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainDate(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-number.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-number.js new file mode 100644 index 0000000000..c57bc4aa1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: A number is invalid in place of an ISO string for Temporal.PlainTime +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2); + +const numbers = [ + 1, + -123456.987654321, + 1234567, + 123456.9876543219, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.withPlainTime(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/PlainDateTime/prototype/withPlainTime/argument-object-insufficient-data.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-object-insufficient-data.js new file mode 100644 index 0000000000..a0532e47d4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-object-insufficient-data.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.plaindatetime.prototype.withplaintime +description: A plain object can be used as an argument +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(2015, 12, 7, 3, 24, 30, 0, 3, 500); + +assert.throws( + TypeError, + () => dt.withPlainTime({}), + "empty object not an acceptable argument" +); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainTime({ hour: 10 }), + 2015, 12, "M12", 7, 10, 0, 0, 0, 0, 0, + "plain object (hour) works" +); + +assert.throws( + TypeError, + () => dt.withPlainTime({ hours: 9 }), // should be "hour", see above + "plain object with a single unrecognized property fails" +); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainTime({ hour: 10, seconds: 123 }), + 2015, 12, "M12", 7, 10, 0, 0, 0, 0, 0, + "unrecognized properties are ignored if at least one recognized property is present" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..5c4d6b028f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..f0535a69b0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainTime(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..eb14fdd13b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.PlainDateTime(1976, 11, 18, 15, 23); + +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.withPlainTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 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.withPlainTime(arg), + `"${arg}" UTC offset without time is not valid for PlainTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..c1c58dd36c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainTime(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..b50a240a48 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainTime(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-no-implicit-midnight.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-no-implicit-midnight.js new file mode 100644 index 0000000000..288d13416c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +assert.throws( + RangeError, + () => instance.withPlainTime(arg), + "Date-only string throws, does not implicitly convert to midnight" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js new file mode 100644 index 0000000000..2fbe0e86ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: ISO 8601 time designator "T" required in cases of ambiguity +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +TemporalHelpers.ISO.plainTimeStringsAmbiguous().forEach((string) => { + let arg = string; + assert.throws( + RangeError, + () => instance.withPlainTime(arg), + `'${arg}' is ambiguous and requires T prefix` + ); + // The same string with a T prefix should not throw: + arg = `T${string}`; + instance.withPlainTime(arg); + + arg = ` ${string}`; + assert.throws( + RangeError, + () => instance.withPlainTime(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.withPlainTime(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-separators.js new file mode 100644 index 0000000000..b7ff3060b6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..ac21c47797 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..837d16ed8e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(1976, 11, 18, 15, 23); + +tests.forEach(([arg, description]) => { + const result = instance.withPlainTime(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1976, 11, "M11", 18, 12, 34, 56, 987, 654, 321, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-with-time-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-with-time-designator.js new file mode 100644 index 0000000000..53f6f8533c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: ISO 8601 time designator "T" allowed at the start of PlainTime strings +includes: [temporalHelpers.js] +features: [Temporal, arrow-function] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 1, 1, 12, 30, 45, 123, 456, 789); +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.withPlainTime(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/PlainDateTime/prototype/withPlainTime/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..60ed3676fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainTime(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/PlainDateTime/prototype/withPlainTime/argument-string-without-time-designator.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-without-time-designator.js new file mode 100644 index 0000000000..2d0af7c731 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-without-time-designator.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.plaindatetime.prototype.withplaintime +description: String argument without ISO 8601 time designator "T" allowed +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(2015, 12, 7, 3, 24, 30, 0, 3, 500); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainTime("12:34"), + 2015, 12, "M12", 7, 12, 34, 0, 0, 0, 0, + "time-like string works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-time.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-time.js new file mode 100644 index 0000000000..51ede37ea3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-time.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.plaindatetime.prototype.withplaintime +description: An instance of PlainTime can be used as an argument +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const dt = new Temporal.PlainDateTime(2015, 12, 7, 3, 24, 30, 0, 3, 500); +const hour = 11; +const minute = 22; +const time = new Temporal.PlainTime(hour, minute); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainTime(time), + 2015, + 12, + "M12", + 7, + hour, + minute, + 0, + 0, + 0, + 0, + "PlainTime argument works" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-wrong-type.js new file mode 100644 index 0000000000..3ce1146118 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +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.withPlainTime(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.withPlainTime(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/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..3fb5f18f0a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.plaindatetime.prototype.withplaintime step 4: + 4. Let _plainTime_ be ? ToTemporalTime(_plainTimeLike_). +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 pdt = new Temporal.PlainDateTime(2000, 5, 2); +const newpdt = pdt.withPlainTime(datetime); + +TemporalHelpers.assertPlainDateTime(newpdt, 2000, 5, "M05", 2, 1, 1, 1, 1, 0, 999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..90134da1be --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321); +const result = instance.withPlainTime(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/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..e96dca9640 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.withPlainTime(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..e916235f4c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => plain.withPlainTime(zoned), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..60d258eda4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(RangeError, () => plain.withPlainTime(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..54d4aabd9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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 plain = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + const zoned = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + assert.throws(TypeError, () => plain.withPlainTime(zoned)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/branding.js new file mode 100644 index 0000000000..cae7cd48bf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const withPlainTime = Temporal.PlainDateTime.prototype.withPlainTime; + +assert.sameValue(typeof withPlainTime, "function"); + +assert.throws(TypeError, () => withPlainTime.call(undefined), "undefined"); +assert.throws(TypeError, () => withPlainTime.call(null), "null"); +assert.throws(TypeError, () => withPlainTime.call(true), "true"); +assert.throws(TypeError, () => withPlainTime.call(""), "empty string"); +assert.throws(TypeError, () => withPlainTime.call(Symbol()), "symbol"); +assert.throws(TypeError, () => withPlainTime.call(1), "1"); +assert.throws(TypeError, () => withPlainTime.call({}), "plain object"); +assert.throws(TypeError, () => withPlainTime.call(Temporal.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => withPlainTime.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/builtin.js new file mode 100644 index 0000000000..3b4d77779a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: > + Tests that Temporal.PlainDateTime.prototype.withPlainTime + 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.PlainDateTime.prototype.withPlainTime), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.withPlainTime), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.withPlainTime), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.PlainDateTime.prototype.withPlainTime.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/leap-second.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/leap-second.js new file mode 100644 index 0000000000..27bab2e006 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Leap second is a valid ISO string for PlainTime +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.withPlainTime(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.withPlainTime(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/PlainDateTime/prototype/withPlainTime/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/length.js new file mode 100644 index 0000000000..d090f2385c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Temporal.PlainDateTime.prototype.withPlainTime.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.PlainDateTime.prototype.withPlainTime, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/name.js new file mode 100644 index 0000000000..ed1b0a27c4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Temporal.PlainDateTime.prototype.withPlainTime.name is "withPlainTime". +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.PlainDateTime.prototype.withPlainTime, "name", { + value: "withPlainTime", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/no-argument-default-to-midnight.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/no-argument-default-to-midnight.js new file mode 100644 index 0000000000..a291dc154a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/no-argument-default-to-midnight.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.plaindatetime.prototype.withplaintime +description: If no argument is given, default to midnight +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const dt = new Temporal.PlainDateTime(2015, 12, 7, 3, 24, 30, 0, 3, 500); + +TemporalHelpers.assertPlainDateTime( + dt.withPlainTime(), + 2015, 12, "M12", 7, 0, 0, 0, 0, 0, 0, + "no argument defaults to midnight" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/not-a-constructor.js new file mode 100644 index 0000000000..f0568aef06 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: > + Temporal.PlainDateTime.prototype.withPlainTime 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.PlainDateTime.prototype.withPlainTime(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.withPlainTime), false, + "isConstructor(Temporal.PlainDateTime.prototype.withPlainTime)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/plaintime-propertybag-no-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/plaintime-propertybag-no-time-units.js new file mode 100644 index 0000000000..a074797a02 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Missing time units in property bag default to 0 +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.PlainDateTime(2000, 1, 1, 12, 30, 45, 123, 456, 789); + +const props = {}; +assert.throws(TypeError, () => instance.withPlainTime(props), "TypeError if no properties are present"); + +props.minute = 30; +const result = instance.withPlainTime(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/PlainDateTime/prototype/withPlainTime/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/prop-desc.js new file mode 100644 index 0000000000..f874bcd013 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: The "withPlainTime" property of Temporal.PlainDateTime.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.PlainDateTime.prototype.withPlainTime, + "function", + "`typeof PlainDateTime.prototype.withPlainTime` is `function`" +); + +verifyProperty(Temporal.PlainDateTime.prototype, "withPlainTime", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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/PlainDateTime/prototype/withPlainTime/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/subclassing-ignored.js new file mode 100644 index 0000000000..a28b2cfc9e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +description: Objects of a subclass are never created as return values. +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkSubclassingIgnored( + Temporal.PlainDateTime, + [2000, 5, 2, 12, 34, 56, 987, 654, 321], + "withPlainTime", + ["05:43:21.123456789"], + (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 5, 43, 21, 123, 456, 789), +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/time-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/time-undefined.js new file mode 100644 index 0000000000..929ea523ea --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/time-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.plaindatetime.prototype.withplaintime +description: The time is assumed to be midnight if not given +features: [Temporal] +---*/ + +const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); + +const explicit = datetime.withPlainTime(undefined); +assert.sameValue(explicit.hour, 0, "default time is midnight"); +assert.sameValue(explicit.minute, 0, "default time is midnight"); +assert.sameValue(explicit.second, 0, "default time is midnight"); +assert.sameValue(explicit.millisecond, 0, "default time is midnight"); +assert.sameValue(explicit.microsecond, 0, "default time is midnight"); +assert.sameValue(explicit.nanosecond, 0, "default time is midnight"); + +const implicit = datetime.withPlainTime(); +assert.sameValue(implicit.hour, 0, "default time is midnight"); +assert.sameValue(implicit.minute, 0, "default time is midnight"); +assert.sameValue(implicit.second, 0, "default time is midnight"); +assert.sameValue(implicit.millisecond, 0, "default time is midnight"); +assert.sameValue(implicit.microsecond, 0, "default time is midnight"); +assert.sameValue(implicit.nanosecond, 0, "default time is midnight"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/year-zero.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/year-zero.js new file mode 100644 index 0000000000..6be051a45f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/withPlainTime/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.plaindatetime.prototype.withplaintime +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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.withPlainTime(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/branding.js new file mode 100644 index 0000000000..71d9222d6d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/branding.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.year +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const year = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => year.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..8fc12c64f9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.year; + +Object.defineProperty(Temporal.Calendar.prototype, "year", yearOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/custom.js new file mode 100644 index 0000000000..f2dfc106bc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "year arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.year; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/prop-desc.js new file mode 100644 index 0000000000..79ae1af772 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/prop-desc.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.plaindatetime.prototype.year +description: The "year" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/year/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/year/validate-calendar-value.js new file mode 100644 index 0000000000..1d35fb8597 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, calendar); + assert.sameValue(instance.year, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/basic.js new file mode 100644 index 0000000000..7f11b118e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/basic.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-get-temporal.plaindatetime.prototype.yearofweek +description: Checking yearOfWeek for a "normal" case (non-undefined, non-boundary case, etc.) +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const datetime = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); +assert.sameValue(datetime.yearOfWeek, 1976, "check yearOfWeek information"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/branding.js new file mode 100644 index 0000000000..01584442eb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.yearofweek +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const yearOfWeek = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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.PlainDateTime), "Temporal.PlainDateTime"); +assert.throws(TypeError, () => yearOfWeek.call(Temporal.PlainDateTime.prototype), "Temporal.PlainDateTime.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/builtin-calendar-no-observable-calls.js new file mode 100644 index 0000000000..ac90671ed2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); +instance.yearOfWeek; + +Object.defineProperty(Temporal.Calendar.prototype, "yearOfWeek", yearOfWeekOriginal); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/custom.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/custom.js new file mode 100644 index 0000000000..2bd3306412 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.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, [pdt], "yearOfWeek arguments"); + return 7; + } +} + +const calendar = new CustomCalendar(); +const pdt = new Temporal.PlainDateTime(1830, 8, 25, 20, 0, 0, 0, 0, 0, calendar); +const result = pdt.yearOfWeek; +assert.sameValue(result, 7, "result"); +assert.sameValue(calls, 1, "calls"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/prop-desc.js new file mode 100644 index 0000000000..43b57c137a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/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.plaindatetime.prototype.yearofweek +description: The "yearOfWeek" property of Temporal.PlainDateTime.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.PlainDateTime.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/PlainDateTime/prototype/yearOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/validate-calendar-value.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/validate-calendar-value.js new file mode 100644 index 0000000000..cd43fd4474 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/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.plaindatetime.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], + ["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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, 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.PlainDateTime(1981, 12, 15, 14, 15, 45, 987, 654, 321, calendar); + assert.sameValue(instance.yearOfWeek, result, `${typeof result} ${String(result)} preserved`); +}); + +reportCompare(0, 0); |