diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/built-ins/Temporal/TimeZone/prototype | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/TimeZone/prototype')
284 files changed, 8190 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/constructor.js new file mode 100644 index 0000000000..b84be5c78b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.constructor +description: Test for Temporal.TimeZone.prototype.constructor. +info: The initial value of Temporal.TimeZone.prototype.constructor is %Temporal.TimeZone%. +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.TimeZone.prototype, "constructor", { + value: Temporal.TimeZone, + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-object.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-object.js new file mode 100644 index 0000000000..196f32b1a9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-object.js @@ -0,0 +1,106 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: Tests that objects can be compared for equality +features: [Temporal] +---*/ + +class CustomTimeZone extends Temporal.TimeZone { + constructor(id) { + super("UTC"); + this._id = id; + } + get id() { + return this._id; + } +} + +const objectsEqualUTC = [ + new Temporal.TimeZone("UTC"), + new CustomTimeZone("UTC"), + { id: "UTC", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + new Temporal.ZonedDateTime(0n, "UTC") +]; + +const tzUTC = new Temporal.TimeZone("UTC"); + +for (const object of objectsEqualUTC) { + const result = tzUTC.equals(object); + assert.sameValue(result, true, `Receiver ${tzUTC.id} should equal argument ${object.id}`); +} + +const objectsEqual0000 = [ + new Temporal.TimeZone("+00:00"), + new Temporal.TimeZone("+0000"), + new Temporal.TimeZone("+00"), + new CustomTimeZone("+00:00"), + new CustomTimeZone("+0000"), + new CustomTimeZone("+00"), + { id: "+00:00", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + { id: "+0000", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + { id: "+00", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + new Temporal.ZonedDateTime(0n, "+00:00"), + new Temporal.ZonedDateTime(0n, "+0000"), + new Temporal.ZonedDateTime(0n, "+00"), + "+00:00", + "+0000", + "+00" +]; + +const tz0000ToTest = [ + new Temporal.TimeZone("+00:00"), + new Temporal.TimeZone("+0000"), + new Temporal.TimeZone("+00"), + new CustomTimeZone("+00:00"), + new CustomTimeZone("+0000"), + new CustomTimeZone("+00") +]; + +for (const arg of objectsEqual0000) { + for (const receiver of tz0000ToTest) { + const result = receiver.equals(arg); + assert.sameValue(result, true, `Receiver ${receiver.id} should equal argument ${arg.id ?? arg}`); + } +} + +const objectsNotEqual = [ + new Temporal.TimeZone("+00:00"), + new CustomTimeZone("+00:00"), + new CustomTimeZone("Etc/Custom"), + { id: "+00:00", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + { id: "Etc/Custom", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }, + new Temporal.ZonedDateTime(0n, "+00:00"), + "UTC" +]; + +const customObjectsToTest = [tzUTC, new CustomTimeZone("YouTeeSee"), new CustomTimeZone("+01:00")]; + +for (const arg of objectsNotEqual) { + for (const receiver of customObjectsToTest) { + if (arg === "UTC" && receiver === tzUTC) continue; + const result = receiver.equals(arg); + assert.sameValue(result, false, `Receiver ${receiver.id} should not equal argument ${arg.id ?? arg}`); + } +} + +// Custom object IDs are compared case-sensitively +const classInstanceCustomId = new CustomTimeZone("Moon/Cheese"); +const classInstanceSameCaseCustomId = new CustomTimeZone("Moon/Cheese"); +const classInstanceDifferentCaseCustomId = new CustomTimeZone("MoOn/CHEESe"); + +const plainObjectSameCaseCustomId = { id: "Moon/Cheese", getPossibleInstantsFor: null, getOffsetNanosecondsFor: null }; +const plainObjectDifferentCaseCustomId = { + id: "MoOn/CHEESe", + getPossibleInstantsFor: null, + getOffsetNanosecondsFor: null +}; + +assert.sameValue(classInstanceCustomId.equals(classInstanceSameCaseCustomId), true); +assert.sameValue(classInstanceCustomId.equals(classInstanceDifferentCaseCustomId), false); +assert.sameValue(classInstanceCustomId.equals(plainObjectSameCaseCustomId), true); +assert.sameValue(classInstanceCustomId.equals(plainObjectDifferentCaseCustomId), false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-primitive.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-primitive.js new file mode 100644 index 0000000000..023206985d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-primitive.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.from +description: Exceptions thrown if a value is passed that converts to an invalid string +features: [Temporal] +---*/ + +const primitives = [ + undefined, + null, + true, + "string", + "local", + "Z", + "-00:00[UTC]", + "+00:01.1", + "-01.1", + "1994-11-05T08:15:30+25:00", + "1994-11-05T13:15:30-25:00", + 7, + 4.2, + 12n +]; + +const tzUTC = new Temporal.TimeZone("UTC"); +for (const primitive of primitives) { + assert.throws(typeof primitive === "string" ? RangeError : TypeError, () => tzUTC.equals(primitive)); +} + +const symbol = Symbol(); +assert.throws(TypeError, () => tzUTC.equals(symbol)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-valid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-valid.js new file mode 100644 index 0000000000..79af622fe4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/argument-valid.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.from +description: Built-in time zones are compared correctly out of valid strings +features: [Temporal] +---*/ + +const validsEqual = [ + ["+0330", "+03:30"], + ["-0650", "-06:50"], + ["-08", "-08:00"], + ["\u221201:00", "-01:00"], + ["\u22120650", "-06:50"], + ["\u221208", "-08:00"], + ["1994-11-05T08:15:30-05:00", "-05:00"], + ["1994-11-05T08:15:30\u221205:00", "-05:00"], + ["1994-11-05T13:15:30Z", "UTC"] +]; + +for (const [valid, canonical] of validsEqual) { + const tzValid = Temporal.TimeZone.from(valid); + const tzCanonical = Temporal.TimeZone.from(canonical); + assert.sameValue(tzValid.equals(canonical), true); + assert.sameValue(tzCanonical.equals(valid), true); +} + +const validsNotEqual = [ + ["+0330", "+03:31"], + ["-0650", "-06:51"], + ["-08", "-08:01"], + ["\u221201:00", "-01:01"], + ["\u22120650", "-06:51"], + ["\u221208", "-08:01"], + ["1994-11-05T08:15:30-05:00", "-05:01"], + ["1994-11-05T08:15:30\u221205:00", "-05:01"] +]; + +for (const [valid, canonical] of validsNotEqual) { + const tzValid = Temporal.TimeZone.from(valid); + const tzCanonical = Temporal.TimeZone.from(canonical); + assert.sameValue(tzValid.equals(canonical), false); + assert.sameValue(tzCanonical.equals(valid), false); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/branding.js new file mode 100644 index 0000000000..5673b192e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/branding.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const equals = Temporal.TimeZone.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +const args = ["UTC"]; + +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.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => equals.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/builtin.js new file mode 100644 index 0000000000..02c46c0d3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/builtin.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: > + Tests that Temporal.TimeZone.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.TimeZone.prototype.equals), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.equals), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.equals), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.equals.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/id-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/id-wrong-type.js new file mode 100644 index 0000000000..b8fa629020 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/id-wrong-type.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: TypeError thrown if time zone reports an id that is not a String +features: [Temporal] +---*/ + +class CustomTimeZone extends Temporal.TimeZone { + constructor(id) { + super("UTC"); + this._id = id; + } + get id() { + return this._id; + } +} + +[ + undefined, + null, + true, + -1000, + Symbol(), + 3600_000_000_000n, + {}, + { + valueOf() { + return 3600_000_000_000; + } + } +].forEach((wrongId) => { + const timeZoneWrong = new CustomTimeZone(wrongId); + const timeZoneOK = new Temporal.TimeZone('UTC'); + assert.throws(TypeError, () => timeZoneWrong.equals(timeZoneOK)); + assert.throws(TypeError, () => timeZoneOK.equals(timeZoneWrong)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/length.js new file mode 100644 index 0000000000..61c65195ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/length.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: Temporal.TimeZone.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.TimeZone.prototype.equals, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/name.js new file mode 100644 index 0000000000..df1828acc7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/name.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: Temporal.TimeZone.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.TimeZone.prototype.equals, "name", { + value: "equals", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/not-a-constructor.js new file mode 100644 index 0000000000..e01067b313 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/not-a-constructor.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: > + Temporal.TimeZone.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.TimeZone.prototype.equals(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.equals), false, + "isConstructor(Temporal.TimeZone.prototype.equals)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..deb16a6e1c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/prop-desc.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.equals +description: The "equals" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.equals, + "function", + "`typeof TimeZone.prototype.equals` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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/TimeZone/prototype/equals/timezone-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-case-insensitive.js new file mode 100644 index 0000000000..28d4a0de6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-case-insensitive.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.equals +description: Time zone names are case insensitive +features: [Temporal] +---*/ + +const timeZone = 'UtC'; +const result = Temporal.TimeZone.from(timeZone); +assert.sameValue(result.equals(timeZone), true); +assert.sameValue(result.equals("+00:00"), false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-datetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-datetime.js new file mode 100644 index 0000000000..56cafca99f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-datetime.js @@ -0,0 +1,64 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.equals +description: Conversion of ISO date-time strings to the argument of Temporal.TimeZone.prototype.equals +features: [Temporal] +---*/ + +let tzUTC = Temporal.TimeZone.from("UTC"); +let arg = "2021-08-19T17:30"; +assert.throws(RangeError, () => tzUTC.equals(arg), "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, + () => tzUTC.equals(timeZone), + `ISO string ${timeZone} with a sub-minute offset is not a valid time zone` + ); +}); + +arg = "2021-08-19T17:30Z"; +tzUTC = Temporal.TimeZone.from(arg); +assert.sameValue(tzUTC.equals(arg), true, "date-time + Z is UTC time zone"); + +arg = "2021-08-19T17:30-07:00"; +tzUTC = Temporal.TimeZone.from(arg); +assert.sameValue(tzUTC.equals(arg), true, "date-time + offset is the offset time zone"); + +arg = "2021-08-19T17:30[UTC]"; +tzUTC = Temporal.TimeZone.from(arg); +assert.sameValue(tzUTC.equals(arg), true, "date-time + IANA annotation is the IANA time zone"); + +arg = "2021-08-19T17:30Z[UTC]"; +tzUTC = Temporal.TimeZone.from(arg); +assert.sameValue(tzUTC.equals(arg), true, "date-time + Z + IANA annotation is the IANA time zone"); + +arg = "2021-08-19T17:30-07:00[UTC]"; +tzUTC = Temporal.TimeZone.from(arg); +assert.sameValue(tzUTC.equals(arg), true, "date-time + offset + IANA annotation is the IANA time zone"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-multiple-offsets.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-multiple-offsets.js new file mode 100644 index 0000000000..2ac68213de --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-string-multiple-offsets.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.from +description: Time zone strings with UTC offset fractional part are not confused with time fractional part +features: [Temporal] +---*/ + +const timeZone = "2021-08-19T17:30:45.123456789-12:12[+01:46]"; + +const result = Temporal.TimeZone.from(timeZone); +assert.sameValue(result.equals("+01:46"), true, "Time zone string determined from bracket name"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-wrong-type.js new file mode 100644 index 0000000000..a0031d3629 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/equals/timezone-wrong-type.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.from +description: > + Appropriate error thrown when argument cannot be converted to a valid string + or object for TimeZone +features: [BigInt, Symbol, Temporal] +---*/ + +const rangeErrorTests = [ + [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"] +]; + +const tzUTC = new Temporal.TimeZone("UTC"); + +for (const [timeZone, description] of rangeErrorTests) { + assert.throws( + typeof timeZone === "string" ? RangeError : TypeError, + () => tzUTC.equals(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, + () => tzUTC.equals(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/TimeZone/prototype/getInstantFor/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..86aeca4e6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-builtin-calendar-no-array-iteration.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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +// Patch getPossibleInstantsFor to allow the spec-mandated observable array +// iteration in the GetPossibleInstantsFor AO. +instance.getPossibleInstantsFor = function (...args) { + const instants = Temporal.TimeZone.prototype.getPossibleInstantsFor.apply(this, args); + instants[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + return instants; +} + +const arg = { year: 2000, month: 5, day: 2, hour: 21, minute: 43, second: 5, calendar: "iso8601" }; +instance.getInstantFor(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js new file mode 100644 index 0000000000..25129f6bbd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js @@ -0,0 +1,21 @@ +// |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.timezone.prototype.getinstantfor +description: Appropriate error thrown when argument cannot be converted to Temporal.PlainDateTime +features: [Temporal] +---*/ + +const timeZone = Temporal.TimeZone.from("UTC"); +assert.throws(TypeError, () => timeZone.getInstantFor(undefined), "undefined"); +assert.throws(TypeError, () => timeZone.getInstantFor(null), "null"); +assert.throws(TypeError, () => timeZone.getInstantFor(true), "boolean"); +assert.throws(RangeError, () => timeZone.getInstantFor(""), "empty string"); +assert.throws(TypeError, () => timeZone.getInstantFor(Symbol()), "Symbol"); +assert.throws(TypeError, () => timeZone.getInstantFor(5), "number"); +assert.throws(TypeError, () => timeZone.getInstantFor(5n), "bigint"); +assert.throws(TypeError, () => timeZone.getInstantFor({ year: 2020 }), "plain object"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-number.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-number.js new file mode 100644 index 0000000000..77e4ea585a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: A number cannot be used in place of a Temporal.PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.getInstantFor(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/TimeZone/prototype/getInstantFor/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-plaindate.js new file mode 100644 index 0000000000..5feb991897 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Fast path for converting Temporal.PlainDate to Temporal.PlainDateTime by reading internal slots +info: | + sec-temporal.timezone.prototype.getinstantfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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) => { + const timezone = new Temporal.TimeZone("UTC"); + const result = timezone.getInstantFor(date); + assert.sameValue(result.epochNanoseconds, 957_225_600_000_000_000n, "epochNanoseconds result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..baa227029c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: The calendar name is case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getInstantFor(arg); +assert.sameValue(result.epochNanoseconds, 217_123_200_000_000_000n, "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..8dbefc0285 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Leap second is a valid ISO string for a calendar in a property bag +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getInstantFor(arg); +assert.sameValue( + result.epochNanoseconds, + 217_123_200_000_000_000n, + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..5c799c9c6c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; + +for (const calendar of numbers) { + const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; + assert.throws( + TypeError, + () => instance.getInstantFor(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..050000cc46 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getInstantFor(arg); +assert.sameValue(result.epochNanoseconds, 217_123_200_000_000_000n, `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..d07432774c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +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.getInstantFor(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.getInstantFor(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/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..8065dd55fe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..1bb66f7648 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getInstantFor(arg); + + assert.sameValue( + result.epochNanoseconds, + 217_178_580_000_000_000n, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..afc68a8834 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..647003b0b1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +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.getInstantFor(arg); + + assert.sameValue( + result.epochNanoseconds, + 217_178_580_000_000_000n, + `"${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.getInstantFor(arg), + `"${arg}" UTC offset without time is not valid for PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..caa6556187 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..94425d1a21 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-time-separators.js new file mode 100644 index 0000000000..dc5b4da151 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getInstantFor(arg); + + assert.sameValue( + result.epochNanoseconds, + 217_178_580_000_000_000n, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..c9bbd70bf1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getInstantFor(arg); + + assert.sameValue( + result.epochNanoseconds, + 217_178_580_000_000_000n, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..7c8a57e644 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getInstantFor(arg); + + assert.sameValue( + result.epochNanoseconds, + 217_178_580_000_000_000n, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..8361128f7e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(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/TimeZone/prototype/getInstantFor/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-wrong-type.js new file mode 100644 index 0000000000..dbc90d6ccd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +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.getInstantFor(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.getInstantFor(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/TimeZone/prototype/getInstantFor/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..fc47684fd3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.timezone.prototype.getinstantfor step 3: + 3. Set _dateTime_ ? ToTemporalDateTime(_dateTime_). +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 conversionTimeZone = new Temporal.TimeZone("UTC"); // should not be used to interpret the argument +const instant = conversionTimeZone.getInstantFor(datetime); + +assert.sameValue(instant.epochNanoseconds, 3661_001_000_999n); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..25e42c9193 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +const result = instance.getInstantFor(datetime); +assert.sameValue(result.epochNanoseconds, -13849764_999_999_999n); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..33e6af18f2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(RangeError, () => builtinTimeZone.getInstantFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..d58be69ae8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => builtinTimeZone.getInstantFor(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..2a9b963652 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(RangeError, () => builtinTimeZone.getInstantFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..3aaeec2514 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(TypeError, () => builtinTimeZone.getInstantFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/balance-negative-time-units.js new file mode 100644 index 0000000000..f8613922bb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.timezone.prototype.getinstantfor step 6: + 6. Return ? 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 +tz.getInstantFor(datetime, { 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/TimeZone/prototype/getInstantFor/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/branding.js new file mode 100644 index 0000000000..d5ea3f0c76 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getInstantFor = Temporal.TimeZone.prototype.getInstantFor; + +assert.sameValue(typeof getInstantFor, "function"); + +const args = [new Temporal.PlainDateTime(2022, 6, 22)]; + +assert.throws(TypeError, () => getInstantFor.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getInstantFor.apply(null, args), "null"); +assert.throws(TypeError, () => getInstantFor.apply(true, args), "true"); +assert.throws(TypeError, () => getInstantFor.apply("", args), "empty string"); +assert.throws(TypeError, () => getInstantFor.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getInstantFor.apply(1, args), "1"); +assert.throws(TypeError, () => getInstantFor.apply({}, args), "plain object"); +assert.throws(TypeError, () => getInstantFor.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getInstantFor.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/builtin.js new file mode 100644 index 0000000000..709f4d3c30 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: > + Tests that Temporal.TimeZone.prototype.getInstantFor + 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.TimeZone.prototype.getInstantFor), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getInstantFor), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getInstantFor), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getInstantFor.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..b3650982ca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.getInstantFor(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/TimeZone/prototype/getInstantFor/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-fields-iterable.js new file mode 100644 index 0000000000..c4a2b8bc1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-fields-iterable.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.timezone.prototype.getinstantfor +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.timezone.prototype.getinstantfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 calendar = TemporalHelpers.calendarFieldsIterable(); +const timeZone = new Temporal.TimeZone("UTC"); +timeZone.getInstantFor({ year: 2000, month: 5, day: 2, calendar }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-temporal-object.js new file mode 100644 index 0000000000..54f820bd2f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.timezone.prototype.getinstantfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 timeZone = new Temporal.TimeZone("UTC"); + timeZone.getInstantFor({ year: 2000, month: 5, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..0404044e4d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +assert.throws(RangeError, () => instance.getInstantFor(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-invalid-string.js new file mode 100644 index 0000000000..2f1c3f3fd2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-invalid-string.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getinstantfor +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.timezone.prototype.getinstantfor 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"); +assert.throws(RangeError, () => timeZone.getInstantFor(datetime, { disambiguation: "other string" })); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-undefined.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-undefined.js new file mode 100644 index 0000000000..f8874c7227 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-undefined.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.timezone.prototype.getinstantfor +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.timezone.prototype.getinstantfor 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 = timeZone.getInstantFor(datetime, { disambiguation: undefined }); + assert.sameValue(explicit.epochNanoseconds, expected, "default disambiguation is compatible"); + const implicit = timeZone.getInstantFor(datetime, {}); + assert.sameValue(implicit.epochNanoseconds, expected, "default disambiguation is compatible"); + const lambda = timeZone.getInstantFor(datetime, () => {}); + assert.sameValue(lambda.epochNanoseconds, expected, "default disambiguation is compatible"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js new file mode 100644 index 0000000000..8184f7cce9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.timezone.prototype.getinstantfor 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) => timeZone.getInstantFor(datetime, { 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/TimeZone/prototype/getInstantFor/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/duplicate-calendar-fields.js new file mode 100644 index 0000000000..b6a8d452a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + + assert.throws(RangeError, () => instance.getInstantFor(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/getpossibleinstantsfor-called-with-iso8601-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/getpossibleinstantsfor-called-with-iso8601-calendar.js new file mode 100644 index 0000000000..b78f801c25 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/getpossibleinstantsfor-called-with-iso8601-calendar.js @@ -0,0 +1,59 @@ +// |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.timezone.prototype.getinstantfor +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"); + +for (const disambiguation of ["earlier", "later", "compatible"]) { + const timeZone = new SkippedDateTime(); + timeZone.getInstantFor(new Temporal.PlainDateTime(2000, 3, 4, 12, 34, 56, 0, 0, 0, nonBuiltinISOCalendar), { disambiguation }); + + 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/TimeZone/prototype/getInstantFor/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..6916cead64 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); +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.getInstantFor({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.getInstantFor({ ...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/TimeZone/prototype/getInstantFor/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/leap-second.js new file mode 100644 index 0000000000..e70881059c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Leap second is a valid ISO string for PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.getInstantFor(arg); +assert.sameValue( + result1.epochNanoseconds, + 1_483_228_799_000_000_000n, + "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.getInstantFor(arg); +assert.sameValue( + result2.epochNanoseconds, + 1_483_228_799_000_000_000n, + "second: 60 is ignored in property bag for PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/length.js new file mode 100644 index 0000000000..d273fcf2a6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Temporal.TimeZone.prototype.getInstantFor.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.TimeZone.prototype.getInstantFor, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/name.js new file mode 100644 index 0000000000..6d07a0e673 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Temporal.TimeZone.prototype.getInstantFor.name is "getInstantFor". +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.TimeZone.prototype.getInstantFor, "name", { + value: "getInstantFor", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/not-a-constructor.js new file mode 100644 index 0000000000..f639a9dc89 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: > + Temporal.TimeZone.prototype.getInstantFor 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.TimeZone.prototype.getInstantFor(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getInstantFor), false, + "isConstructor(Temporal.TimeZone.prototype.getInstantFor)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-object.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-object.js new file mode 100644 index 0000000000..1aa686d763 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: Empty or a function object may be used as options +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const result1 = instance.getInstantFor(new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38), {}); +assert.sameValue( + result1.epochNanoseconds, 1572345998000000000n, + "options may be an empty plain object" +); + +const result2 = instance.getInstantFor(new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38), () => {}); +assert.sameValue( + result2.epochNanoseconds, 1572345998000000000n, + "options may be a function object" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-undefined.js new file mode 100644 index 0000000000..6ddd03d9ef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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 = timeZone.getInstantFor(datetime, undefined); + assert.sameValue(explicit.epochNanoseconds, expected, "default disambiguation is compatible"); + + const implicit = timeZone.getInstantFor(datetime); + assert.sameValue(implicit.epochNanoseconds, expected, "default disambiguation is compatible"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/options-wrong-type.js new file mode 100644 index 0000000000..4806f4de41 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: TypeError thrown when options argument is a primitive +features: [BigInt, Symbol, Temporal] +---*/ + +const badOptions = [ + null, + true, + "some string", + Symbol(), + 1, + 2n, +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const value of badOptions) { + assert.throws(TypeError, () => instance.getInstantFor(new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38), value), + `TypeError on wrong options type ${typeof value}`); +}; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js new file mode 100644 index 0000000000..4705daa151 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js @@ -0,0 +1,109 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getinstantfor +description: Properties on an object passed to getInstantFor() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // GetTemporalCalendarSlotValueWithISODefault + "get fields.calendar", + "has fields.calendar.dateAdd", + "has fields.calendar.dateFromFields", + "has fields.calendar.dateUntil", + "has fields.calendar.day", + "has fields.calendar.dayOfWeek", + "has fields.calendar.dayOfYear", + "has fields.calendar.daysInMonth", + "has fields.calendar.daysInWeek", + "has fields.calendar.daysInYear", + "has fields.calendar.fields", + "has fields.calendar.id", + "has fields.calendar.inLeapYear", + "has fields.calendar.mergeFields", + "has fields.calendar.month", + "has fields.calendar.monthCode", + "has fields.calendar.monthDayFromFields", + "has fields.calendar.monthsInYear", + "has fields.calendar.weekOfYear", + "has fields.calendar.year", + "has fields.calendar.yearMonthFromFields", + "has fields.calendar.yearOfWeek", + // lookup + "get fields.calendar.dateFromFields", + "get fields.calendar.fields", + // CalendarFields + "call fields.calendar.fields", + // PrepareTemporalFields + "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", + // InterpretTemporalDateTimeFields + "call fields.calendar.dateFromFields", + // ToTemporalDisambiguation + "get options.disambiguation", + "get options.disambiguation.toString", + "call options.disambiguation.toString", + // BuiltinTimeZoneGetInstantFor + "get this.getPossibleInstantsFor", + "call this.getPossibleInstantsFor", +]; +const actual = []; + +const instance = new Temporal.TimeZone("UTC"); +TemporalHelpers.observeProperty(actual, instance, "getPossibleInstantsFor", function getPossibleInstantsFor(...args) { + actual.push("call this.getPossibleInstantsFor"); + return Temporal.TimeZone.prototype.getPossibleInstantsFor.apply(instance, args); +}, "this"); + +const fields = 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, "fields.calendar"), +}, "fields"); + +const options = TemporalHelpers.propertyBagObserver(actual, { disambiguation: "compatible" }, "options"); + +instance.getInstantFor(fields, options); +assert.compareArray(actual, expected, "order of operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/prop-desc.js new file mode 100644 index 0000000000..444a2d5e2a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: The "getInstantFor" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getInstantFor, + "function", + "`typeof TimeZone.prototype.getInstantFor` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getInstantFor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/proto-in-calendar-fields.js new file mode 100644 index 0000000000..e9dfd7a26f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); + +assert.throws(RangeError, () => instance.getInstantFor(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..87f11aac7f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.timezone.prototype.getinstantfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 timezone = new Temporal.TimeZone("UTC"); +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const result = timezone.getInstantFor({ year: 1970, month: 1, day: 1, calendar }); + +assert.sameValue(result.epochNanoseconds, 0n, "epochNanoseconds result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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/TimeZone/prototype/getInstantFor/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/year-zero.js new file mode 100644 index 0000000000..3cdf65fe5b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getInstantFor/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.timezone.prototype.getinstantfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getInstantFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..7fc69d9415 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-calendar-annotation.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getnexttransition +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[u-ca=iso8601]", "without time zone"], + ["1970-01-01T00:00Z[UTC][u-ca=gregory]", "with time zone"], + ["1970-01-01T00:00Z[!u-ca=hebrew]", "with ! and no time zone"], + ["1970-01-01T00:00Z[UTC][!u-ca=chinese]", "with ! and time zone"], + ["1970-01-01T00:00Z[u-ca=discord]", "annotation is ignored"], + ["1970-01-01T00:00Z[!u-ca=discord]", "annotation with ! is ignored"], + ["1970-01-01T00:00Z[u-ca=iso8601][u-ca=discord]", "two annotations are ignored"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getNextTransition(arg); + + assert.sameValue( + result, + null, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..ea1c71ca90 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar]", + "1970-01-01T00:00Z[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00Z[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getNextTransition(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..1521a8cd4d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getnexttransition +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const validStrings = [ + "1970-01-01T00Z", + "1970-01-01T00Z[UTC]", + "1970-01-01T00Z[!UTC]", + "1970-01-01T00Z[Europe/Vienna]", + "1970-01-01T00+00:00", + "1970-01-01T00+00:00[UTC]", + "1970-01-01T00+00:00[!UTC]", + "1969-12-31T16-08:00[America/Vancouver]", +]; + +for (const arg of validStrings) { + const result = instance.getNextTransition(arg); + + assert.sameValue( + result, + null, + `"${arg}" is a valid UTC offset with time for Instant` + ); +} + +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.getNextTransition(arg), + `"${arg}" UTC offset without time is not valid for Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-invalid.js new file mode 100644 index 0000000000..fdb1c6a0f8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getnexttransition +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as an Instant +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00T00:00Z", + "2020-01-32T00:00Z", + "2020-02-30T00:00Z", + "2021-02-29T00:00Z", + "2020-00-01T00:00Z", + "2020-13-01T00:00Z", + "2020-01-01TZ", + "2020-01-01T25:00:00Z", + "2020-01-01T01:60:00Z", + "2020-01-01T01:60:61Z", + "2020-01-01T00:00Zjunk", + "2020-01-01T00:00:00Zjunk", + "2020-01-01T00:00:00.000000000Zjunk", + "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-01T00:00Z", + "2020-001-01T00:00Z", + "2020-01-001T00:00Z", + "2020-01-01T001Z", + "2020-01-01T01:001Z", + "2020-01-01T01:01:001Z", + // valid, but forms not supported in Temporal: + "2020-W01-1T00:00Z", + "2020-001T00:00Z", + "+0002020-01-01T00:00Z", + // may be valid in other contexts, but insufficient information for Instant: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + "2020-01-01", + "2020-01-01T00", + "2020-01-01T00:00", + "2020-01-01T00:00:00", + "2020-01-01T00:00:00.000000000", + // valid, but outside the supported range: + "-999999-01-01T00:00Z", + "+999999-01-01T00:00Z", +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.getNextTransition(arg), + `"${arg}" should not be a valid ISO string for an Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..f4aa8ca87f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-calendar.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.timezone.prototype.getnexttransition +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getNextTransition(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..bfed54adfe --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[UTC][UTC]", + "1970-01-01T00:00Z[!UTC][UTC]", + "1970-01-01T00:00Z[UTC][!UTC]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00Z[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getNextTransition(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-time-separators.js new file mode 100644 index 0000000000..153d328c87 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z", "uppercase T"], + ["1970-01-01t00:00Z", "lowercase T"], + ["1970-01-01 00:00Z", "space between date and time"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getNextTransition(arg); + + assert.sameValue( + result, + null, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..efaf2f44b3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[Asia/Kolkata]", "named, with Z"], + ["1970-01-01T00:00Z[!Europe/Vienna]", "named, with Z and !"], + ["1970-01-01T00:00Z[+00:00]", "numeric, with Z"], + ["1970-01-01T00:00Z[!-02:30]", "numeric, with Z and !"], + ["1970-01-01T00:00+00:00[UTC]", "named, with offset"], + ["1970-01-01T00:00+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1970-01-01T00:00+00:00[-08:00]", "numeric, with offset"], + ["1970-01-01T00:00+00:00[!+01:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getNextTransition(arg); + + assert.sameValue( + result, + null, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..e465d767d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[foo=bar]", "alone"], + ["1970-01-01T00:00Z[UTC][foo=bar]", "with time zone"], + ["1970-01-01T00:00Z[u-ca=iso8601][foo=bar]", "with calendar"], + ["1970-01-01T00:00Z[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1970-01-01T00:00Z[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getNextTransition(arg); + + assert.sameValue( + result, + null, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-wrong-type.js new file mode 100644 index 0000000000..b89dfe2520 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-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.timezone.prototype.getnexttransition +description: > + Appropriate error thrown when argument cannot be converted to a valid string + for Instant +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const primitiveTests = [ + [undefined, "undefined"], + [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"], + [{}, "plain object"], + [Temporal.Instant, "Temporal.Instant, object"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === "string" || (typeof arg === "object" && arg !== null) || typeof arg === "function" + ? RangeError + : TypeError, + () => instance.getNextTransition(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [Temporal.Instant.prototype, "Temporal.Instant.prototype, object"], // fails brand check in toString() +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.getNextTransition(arg), `${description} does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.js new file mode 100644 index 0000000000..74217f32ae --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.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.timezone.prototype.getnexttransition +description: Fast path for converting Temporal.ZonedDateTime to Temporal.Instant +info: | + sec-temporal.timezone.prototype.getnexttransition step 3: + 3. Set _startingPoint_ to ? ToTemporalInstant(_startingPoint_). + sec-temporal-totemporalinstant step 1.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return ! CreateTemporalInstant(_item_.[[Nanoseconds]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalInstantFastPath((datetime) => { + const timeZone = Temporal.TimeZone.from("UTC"); + const result = timeZone.getNextTransition(datetime); + assert.sameValue(result, null, "transition result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/branding.js new file mode 100644 index 0000000000..c78e545d10 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getNextTransition = Temporal.TimeZone.prototype.getNextTransition; + +assert.sameValue(typeof getNextTransition, "function"); + +const args = [new Temporal.Instant(0n)]; + +assert.throws(TypeError, () => getNextTransition.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getNextTransition.apply(null, args), "null"); +assert.throws(TypeError, () => getNextTransition.apply(true, args), "true"); +assert.throws(TypeError, () => getNextTransition.apply("", args), "empty string"); +assert.throws(TypeError, () => getNextTransition.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getNextTransition.apply(1, args), "1"); +assert.throws(TypeError, () => getNextTransition.apply({}, args), "plain object"); +assert.throws(TypeError, () => getNextTransition.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getNextTransition.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/builtin.js new file mode 100644 index 0000000000..c63cf94509 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: > + Tests that Temporal.TimeZone.prototype.getNextTransition + 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.TimeZone.prototype.getNextTransition), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getNextTransition), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getNextTransition), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getNextTransition.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js new file mode 100644 index 0000000000..769699dcfd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.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.timezone.prototype.getnexttransition +description: String arguments at the limit of the representable range +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const minInstantStrings = [ + "-271821-04-20T00:00Z", + "-271821-04-19T23:00-01:00", + "-271821-04-19T00:00:00.000000001-23:59:59.999999999", +]; +for (const str of minInstantStrings) { + assert.sameValue(instance.getNextTransition(str), null, `instant string ${str} should be valid`); +} + +const maxInstantStrings = [ + "+275760-09-13T00:00Z", + "+275760-09-13T01:00+01:00", + "+275760-09-13T23:59:59.999999999+23:59:59.999999999", +]; + +for (const str of maxInstantStrings) { + assert.sameValue(instance.getNextTransition(str), null, `instant string ${str} should be valid`); +} + +const outOfRangeInstantStrings = [ + "-271821-04-19T23:59:59.999999999Z", + "-271821-04-19T23:00-00:59:59.999999999", + "-271821-04-19T00:00:00-23:59:59.999999999", + "-271821-04-19T00:00:00-24:00", + "+275760-09-13T00:00:00.000000001Z", + "+275760-09-13T01:00+00:59:59.999999999", + "+275760-09-14T00:00+23:59:59.999999999", + "+275760-09-14T00:00+24:00", +]; + +for (const str of outOfRangeInstantStrings) { + assert.throws(RangeError, () => instance.getNextTransition(str), `instant string ${str} should not be valid`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string.js new file mode 100644 index 0000000000..eb54738370 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getnexttransition +description: Conversion of ISO date-time strings to Temporal.Instant instances +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let str = "1970-01-01T00:00"; +assert.throws(RangeError, () => instance.getNextTransition(str), "bare date-time string is not an instant"); +str = "1970-01-01T00:00[UTC]"; +assert.throws(RangeError, () => instance.getNextTransition(str), "date-time + IANA annotation is not an instant"); + +// The following are all valid strings so should not throw: + +const valids = [ + "1970-01-01T00:00Z", + "1970-01-01T00:00+01:00", + "1970-01-01T00:00Z[UTC]", + "1970-01-01T00:00+01:00[UTC]", + "1970-01-01T00:00Z[u-ca=hebrew]", + "1970-01-01T00:00+01:00[u-ca=hebrew]", + "1970-01-01T00:00+01:00[Etc/Ignored][u-ca=hebrew]", +]; +for (const str of valids) { + const result = instance.getNextTransition(str); + assert.sameValue(result, null); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/leap-second.js new file mode 100644 index 0000000000..e7270bcb82 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/leap-second.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.timezone.prototype.getnexttransition +description: Leap second is a valid ISO string for Instant +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60Z"; +const result = instance.getNextTransition(arg); +assert.sameValue( + result, + null, + "leap second is a valid ISO string for Instant" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/length.js new file mode 100644 index 0000000000..15bda53094 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Temporal.TimeZone.prototype.getNextTransition.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.TimeZone.prototype.getNextTransition, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/name.js new file mode 100644 index 0000000000..2da5b50bdd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Temporal.TimeZone.prototype.getNextTransition.name is "getNextTransition". +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.TimeZone.prototype.getNextTransition, "name", { + value: "getNextTransition", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/not-a-constructor.js new file mode 100644 index 0000000000..7685a1cc62 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: > + Temporal.TimeZone.prototype.getNextTransition 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.TimeZone.prototype.getNextTransition(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getNextTransition), false, + "isConstructor(Temporal.TimeZone.prototype.getNextTransition)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/prop-desc.js new file mode 100644 index 0000000000..eeedb1647c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: The "getNextTransition" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getNextTransition, + "function", + "`typeof TimeZone.prototype.getNextTransition` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getNextTransition", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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/TimeZone/prototype/getNextTransition/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/year-zero.js new file mode 100644 index 0000000000..0c65c5f647 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getNextTransition/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.timezone.prototype.getnexttransition +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-03-30T00:45Z", + "-000000-03-30T01:45+01:00", + "-000000-03-30T01:45:00+00:00[UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getNextTransition(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..082b498e9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-calendar-annotation.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetnanosecondsfor +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[u-ca=iso8601]", "without time zone"], + ["1970-01-01T00:00Z[UTC][u-ca=gregory]", "with time zone"], + ["1970-01-01T00:00Z[!u-ca=hebrew]", "with ! and no time zone"], + ["1970-01-01T00:00Z[UTC][!u-ca=chinese]", "with ! and time zone"], + ["1970-01-01T00:00Z[u-ca=discord]", "annotation is ignored"], + ["1970-01-01T00:00Z[!u-ca=discord]", "annotation with ! is ignored"], + ["1970-01-01T00:00Z[u-ca=iso8601][u-ca=discord]", "two annotations are ignored"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetNanosecondsFor(arg); + + assert.sameValue( + result, + 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..e90272191d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar]", + "1970-01-01T00:00Z[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00Z[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetNanosecondsFor(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..af93408ea2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetnanosecondsfor +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const validStrings = [ + "1970-01-01T00Z", + "1970-01-01T00Z[UTC]", + "1970-01-01T00Z[!UTC]", + "1970-01-01T00Z[Europe/Vienna]", + "1970-01-01T00+00:00", + "1970-01-01T00+00:00[UTC]", + "1970-01-01T00+00:00[!UTC]", + "1969-12-31T16-08:00[America/Vancouver]", +]; + +for (const arg of validStrings) { + const result = instance.getOffsetNanosecondsFor(arg); + + assert.sameValue( + result, + 0, + `"${arg}" is a valid UTC offset with time for Instant` + ); +} + +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.getOffsetNanosecondsFor(arg), + `"${arg}" UTC offset without time is not valid for Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-invalid.js new file mode 100644 index 0000000000..ef406af8ff --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetnanosecondsfor +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as an Instant +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00T00:00Z", + "2020-01-32T00:00Z", + "2020-02-30T00:00Z", + "2021-02-29T00:00Z", + "2020-00-01T00:00Z", + "2020-13-01T00:00Z", + "2020-01-01TZ", + "2020-01-01T25:00:00Z", + "2020-01-01T01:60:00Z", + "2020-01-01T01:60:61Z", + "2020-01-01T00:00Zjunk", + "2020-01-01T00:00:00Zjunk", + "2020-01-01T00:00:00.000000000Zjunk", + "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-01T00:00Z", + "2020-001-01T00:00Z", + "2020-01-001T00:00Z", + "2020-01-01T001Z", + "2020-01-01T01:001Z", + "2020-01-01T01:01:001Z", + // valid, but forms not supported in Temporal: + "2020-W01-1T00:00Z", + "2020-001T00:00Z", + "+0002020-01-01T00:00Z", + // may be valid in other contexts, but insufficient information for Instant: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + "2020-01-01", + "2020-01-01T00", + "2020-01-01T00:00", + "2020-01-01T00:00:00", + "2020-01-01T00:00:00.000000000", + // valid, but outside the supported range: + "-999999-01-01T00:00Z", + "+999999-01-01T00:00Z", +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.getOffsetNanosecondsFor(arg), + `"${arg}" should not be a valid ISO string for an Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..147399f6e3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-calendar.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.timezone.prototype.getoffsetnanosecondsfor +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetNanosecondsFor(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..67630022fc --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[UTC][UTC]", + "1970-01-01T00:00Z[!UTC][UTC]", + "1970-01-01T00:00Z[UTC][!UTC]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00Z[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetNanosecondsFor(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-time-separators.js new file mode 100644 index 0000000000..7ab302d033 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z", "uppercase T"], + ["1970-01-01t00:00Z", "lowercase T"], + ["1970-01-01 00:00Z", "space between date and time"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetNanosecondsFor(arg); + + assert.sameValue( + result, + 0, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..9748b0ceb9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[Asia/Kolkata]", "named, with Z"], + ["1970-01-01T00:00Z[!Europe/Vienna]", "named, with Z and !"], + ["1970-01-01T00:00Z[+00:00]", "numeric, with Z"], + ["1970-01-01T00:00Z[!-02:30]", "numeric, with Z and !"], + ["1970-01-01T00:00+00:00[UTC]", "named, with offset"], + ["1970-01-01T00:00+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1970-01-01T00:00+00:00[-08:00]", "numeric, with offset"], + ["1970-01-01T00:00+00:00[!+01:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetNanosecondsFor(arg); + + assert.sameValue( + result, + 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..f42373402a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[foo=bar]", "alone"], + ["1970-01-01T00:00Z[UTC][foo=bar]", "with time zone"], + ["1970-01-01T00:00Z[u-ca=iso8601][foo=bar]", "with calendar"], + ["1970-01-01T00:00Z[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1970-01-01T00:00Z[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetNanosecondsFor(arg); + + assert.sameValue( + result, + 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-wrong-type.js new file mode 100644 index 0000000000..23653301fa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-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.timezone.prototype.getoffsetnanosecondsfor +description: > + Appropriate error thrown when argument cannot be converted to a valid string + for Instant +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const primitiveTests = [ + [undefined, "undefined"], + [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"], + [{}, "plain object"], + [Temporal.Instant, "Temporal.Instant, object"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === "string" || (typeof arg === "object" && arg !== null) || typeof arg === "function" + ? RangeError + : TypeError, + () => instance.getOffsetNanosecondsFor(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [Temporal.Instant.prototype, "Temporal.Instant.prototype, object"], // fails brand check in toString() +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.getOffsetNanosecondsFor(arg), `${description} does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.js new file mode 100644 index 0000000000..f48f6cc84c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.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.timezone.prototype.getoffsetnanosecondsfor +description: Fast path for converting Temporal.ZonedDateTime to Temporal.Instant +info: | + sec-temporal.timezone.prototype.getoffsetnanosecondsfor step 3: + 3. Set _instant_ to ? ToTemporalInstant(_instant_). + sec-temporal-totemporalinstant step 1.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return ! CreateTemporalInstant(_item_.[[Nanoseconds]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalInstantFastPath((datetime) => { + const timeZone = Temporal.TimeZone.from("UTC"); + const result = timeZone.getOffsetNanosecondsFor(datetime); + assert.sameValue(result, 0, "offset result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/branding.js new file mode 100644 index 0000000000..f7450dd176 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getOffsetNanosecondsFor = Temporal.TimeZone.prototype.getOffsetNanosecondsFor; + +assert.sameValue(typeof getOffsetNanosecondsFor, "function"); + +const args = [new Temporal.Instant(0n)]; + +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(null, args), "null"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(true, args), "true"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply("", args), "empty string"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(1, args), "1"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply({}, args), "plain object"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getOffsetNanosecondsFor.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/builtin.js new file mode 100644 index 0000000000..abc493fc9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: > + Tests that Temporal.TimeZone.prototype.getOffsetNanosecondsFor + 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.TimeZone.prototype.getOffsetNanosecondsFor), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getOffsetNanosecondsFor), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getOffsetNanosecondsFor), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getOffsetNanosecondsFor.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js new file mode 100644 index 0000000000..e2714c7819 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.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.timezone.prototype.getoffsetnanosecondsfor +description: String arguments at the limit of the representable range +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const minInstantStrings = [ + "-271821-04-20T00:00Z", + "-271821-04-19T23:00-01:00", + "-271821-04-19T00:00:00.000000001-23:59:59.999999999", +]; +for (const str of minInstantStrings) { + assert.sameValue(instance.getOffsetNanosecondsFor(str), 0, `instant string ${str} should be valid`); +} + +const maxInstantStrings = [ + "+275760-09-13T00:00Z", + "+275760-09-13T01:00+01:00", + "+275760-09-13T23:59:59.999999999+23:59:59.999999999", +]; + +for (const str of maxInstantStrings) { + assert.sameValue(instance.getOffsetNanosecondsFor(str), 0, `instant string ${str} should be valid`); +} + +const outOfRangeInstantStrings = [ + "-271821-04-19T23:59:59.999999999Z", + "-271821-04-19T23:00-00:59:59.999999999", + "-271821-04-19T00:00:00-23:59:59.999999999", + "-271821-04-19T00:00:00-24:00", + "+275760-09-13T00:00:00.000000001Z", + "+275760-09-13T01:00+00:59:59.999999999", + "+275760-09-14T00:00+23:59:59.999999999", + "+275760-09-14T00:00+24:00", +]; + +for (const str of outOfRangeInstantStrings) { + assert.throws(RangeError, () => instance.getOffsetNanosecondsFor(str), `instant string ${str} should not be valid`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string.js new file mode 100644 index 0000000000..455ea14865 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetnanosecondsfor +description: Conversion of ISO date-time strings to Temporal.Instant instances +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let str = "1970-01-01T00:00"; +assert.throws(RangeError, () => instance.getOffsetNanosecondsFor(str), "bare date-time string is not an instant"); +str = "1970-01-01T00:00[UTC]"; +assert.throws(RangeError, () => instance.getOffsetNanosecondsFor(str), "date-time + IANA annotation is not an instant"); + +// The following are all valid strings so should not throw: + +const valids = [ + "1970-01-01T00:00Z", + "1970-01-01T00:00+01:00", + "1970-01-01T00:00Z[UTC]", + "1970-01-01T00:00+01:00[UTC]", + "1970-01-01T00:00Z[u-ca=hebrew]", + "1970-01-01T00:00+01:00[u-ca=hebrew]", + "1970-01-01T00:00+01:00[Etc/Ignored][u-ca=hebrew]", +]; +for (const str of valids) { + const result = instance.getOffsetNanosecondsFor(str); + assert.sameValue(result, 0); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/leap-second.js new file mode 100644 index 0000000000..1fb52dbb1d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/leap-second.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.timezone.prototype.getoffsetnanosecondsfor +description: Leap second is a valid ISO string for Instant +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60Z"; +const result = instance.getOffsetNanosecondsFor(arg); +assert.sameValue( + result, + 0, + "leap second is a valid ISO string for Instant" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/length.js new file mode 100644 index 0000000000..9a9a560997 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Temporal.TimeZone.prototype.getOffsetNanosecondsFor.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.TimeZone.prototype.getOffsetNanosecondsFor, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/name.js new file mode 100644 index 0000000000..83bf240147 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Temporal.TimeZone.prototype.getOffsetNanosecondsFor.name is "getOffsetNanosecondsFor". +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.TimeZone.prototype.getOffsetNanosecondsFor, "name", { + value: "getOffsetNanosecondsFor", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/not-a-constructor.js new file mode 100644 index 0000000000..c8dc628507 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: > + Temporal.TimeZone.prototype.getOffsetNanosecondsFor 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.TimeZone.prototype.getOffsetNanosecondsFor(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getOffsetNanosecondsFor), false, + "isConstructor(Temporal.TimeZone.prototype.getOffsetNanosecondsFor)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/prop-desc.js new file mode 100644 index 0000000000..5a077f9087 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: The "getOffsetNanosecondsFor" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getOffsetNanosecondsFor, + "function", + "`typeof TimeZone.prototype.getOffsetNanosecondsFor` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getOffsetNanosecondsFor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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/TimeZone/prototype/getOffsetNanosecondsFor/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/year-zero.js new file mode 100644 index 0000000000..c71e09cdf3 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/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.timezone.prototype.getoffsetnanosecondsfor +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-03-30T00:45Z", + "-000000-03-30T01:45+01:00", + "-000000-03-30T01:45:00+00:00[UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetNanosecondsFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js new file mode 100644 index 0000000000..6db17f2203 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.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.timezone.prototype.getoffsetstringfor +description: timeZone.getOffsetNanosecondsFor not called when argument cannot be converted to Temporal.Instant +features: [Temporal] +---*/ + +const timeZone = Temporal.TimeZone.from("UTC"); +let called = false; +timeZone.getOffsetNanosecondsFor = () => called = true; +assert.throws(TypeError, () => timeZone.getOffsetStringFor(undefined), "undefined"); +assert.throws(TypeError, () => timeZone.getOffsetStringFor(null), "null"); +assert.throws(TypeError, () => timeZone.getOffsetStringFor(true), "boolean"); +assert.throws(RangeError, () => timeZone.getOffsetStringFor(""), "empty string"); +assert.throws(TypeError, () => timeZone.getOffsetStringFor(Symbol()), "Symbol"); +assert.throws(TypeError, () => timeZone.getOffsetStringFor(5), "number"); +assert.throws(TypeError, () => timeZone.getOffsetStringFor(5n), "bigint"); +assert.throws(RangeError, () => timeZone.getOffsetStringFor({}), "plain object"); +assert.sameValue(called, false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..b943ca04b0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-calendar-annotation.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[u-ca=iso8601]", "without time zone"], + ["1970-01-01T00:00Z[UTC][u-ca=gregory]", "with time zone"], + ["1970-01-01T00:00Z[!u-ca=hebrew]", "with ! and no time zone"], + ["1970-01-01T00:00Z[UTC][!u-ca=chinese]", "with ! and time zone"], + ["1970-01-01T00:00Z[u-ca=discord]", "annotation is ignored"], + ["1970-01-01T00:00Z[!u-ca=discord]", "annotation with ! is ignored"], + ["1970-01-01T00:00Z[u-ca=iso8601][u-ca=discord]", "two annotations are ignored"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetStringFor(arg); + + assert.sameValue( + result, + "+00:00", + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..86c1b0beef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar]", + "1970-01-01T00:00Z[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00Z[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetStringFor(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..9b40603406 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const validStrings = [ + "1970-01-01T00Z", + "1970-01-01T00Z[UTC]", + "1970-01-01T00Z[!UTC]", + "1970-01-01T00Z[Europe/Vienna]", + "1970-01-01T00+00:00", + "1970-01-01T00+00:00[UTC]", + "1970-01-01T00+00:00[!UTC]", + "1969-12-31T16-08:00[America/Vancouver]", +]; + +for (const arg of validStrings) { + const result = instance.getOffsetStringFor(arg); + + assert.sameValue( + result, + "+00:00", + `"${arg}" is a valid UTC offset with time for Instant` + ); +} + +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.getOffsetStringFor(arg), + `"${arg}" UTC offset without time is not valid for Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-invalid.js new file mode 100644 index 0000000000..f79f971678 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as an Instant +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00T00:00Z", + "2020-01-32T00:00Z", + "2020-02-30T00:00Z", + "2021-02-29T00:00Z", + "2020-00-01T00:00Z", + "2020-13-01T00:00Z", + "2020-01-01TZ", + "2020-01-01T25:00:00Z", + "2020-01-01T01:60:00Z", + "2020-01-01T01:60:61Z", + "2020-01-01T00:00Zjunk", + "2020-01-01T00:00:00Zjunk", + "2020-01-01T00:00:00.000000000Zjunk", + "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-01T00:00Z", + "2020-001-01T00:00Z", + "2020-01-001T00:00Z", + "2020-01-01T001Z", + "2020-01-01T01:001Z", + "2020-01-01T01:01:001Z", + // valid, but forms not supported in Temporal: + "2020-W01-1T00:00Z", + "2020-001T00:00Z", + "+0002020-01-01T00:00Z", + // may be valid in other contexts, but insufficient information for Instant: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + "2020-01-01", + "2020-01-01T00", + "2020-01-01T00:00", + "2020-01-01T00:00:00", + "2020-01-01T00:00:00.000000000", + // valid, but outside the supported range: + "-999999-01-01T00:00Z", + "+999999-01-01T00:00Z", +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.getOffsetStringFor(arg), + `"${arg}" should not be a valid ISO string for an Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..bfd20cc7bb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-calendar.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.timezone.prototype.getoffsetstringfor +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetStringFor(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..a932833b66 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[UTC][UTC]", + "1970-01-01T00:00Z[!UTC][UTC]", + "1970-01-01T00:00Z[UTC][!UTC]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00Z[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetStringFor(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-time-separators.js new file mode 100644 index 0000000000..6568bbc3e4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z", "uppercase T"], + ["1970-01-01t00:00Z", "lowercase T"], + ["1970-01-01 00:00Z", "space between date and time"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetStringFor(arg); + + assert.sameValue( + result, + "+00:00", + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..b158b605e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[Asia/Kolkata]", "named, with Z"], + ["1970-01-01T00:00Z[!Europe/Vienna]", "named, with Z and !"], + ["1970-01-01T00:00Z[+00:00]", "numeric, with Z"], + ["1970-01-01T00:00Z[!-02:30]", "numeric, with Z and !"], + ["1970-01-01T00:00+00:00[UTC]", "named, with offset"], + ["1970-01-01T00:00+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1970-01-01T00:00+00:00[-08:00]", "numeric, with offset"], + ["1970-01-01T00:00+00:00[!+01:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetStringFor(arg); + + assert.sameValue( + result, + "+00:00", + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..6903345bba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[foo=bar]", "alone"], + ["1970-01-01T00:00Z[UTC][foo=bar]", "with time zone"], + ["1970-01-01T00:00Z[u-ca=iso8601][foo=bar]", "with calendar"], + ["1970-01-01T00:00Z[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1970-01-01T00:00Z[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getOffsetStringFor(arg); + + assert.sameValue( + result, + "+00:00", + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-wrong-type.js new file mode 100644 index 0000000000..d64c058d3c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-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.timezone.prototype.getoffsetstringfor +description: > + Appropriate error thrown when argument cannot be converted to a valid string + for Instant +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const primitiveTests = [ + [undefined, "undefined"], + [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"], + [{}, "plain object"], + [Temporal.Instant, "Temporal.Instant, object"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === "string" || (typeof arg === "object" && arg !== null) || typeof arg === "function" + ? RangeError + : TypeError, + () => instance.getOffsetStringFor(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [Temporal.Instant.prototype, "Temporal.Instant.prototype, object"], // fails brand check in toString() +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.getOffsetStringFor(arg), `${description} does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.js new file mode 100644 index 0000000000..38ce243810 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.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.timezone.prototype.getoffsetstringfor +description: Fast path for converting Temporal.ZonedDateTime to Temporal.Instant +info: | + sec-temporal.timezone.prototype.getoffsetstringfor step 3: + 3. Set _instant_ to ? ToTemporalInstant(_instant_). + sec-temporal-totemporalinstant step 1.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return ! CreateTemporalInstant(_item_.[[Nanoseconds]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalInstantFastPath((datetime) => { + const timeZone = Temporal.TimeZone.from("UTC"); + const result = timeZone.getOffsetStringFor(datetime); + assert.sameValue(result, "+00:00", "offset result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/basic.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/basic.js new file mode 100644 index 0000000000..cf45188e28 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/basic.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.timezone.prototype.getoffsetstringfor +description: Basic tests for Temporal.TimeZone.prototype.getOffsetStringFor +features: [BigInt, Temporal] +---*/ + +const instant = new Temporal.Instant(0n); + +function test(timeZoneIdentifier, expectedOffsetString, description) { + const timeZone = new Temporal.TimeZone(timeZoneIdentifier); + assert.sameValue(timeZone.getOffsetStringFor(instant), expectedOffsetString, description); +} + +test("UTC", "+00:00", "offset of UTC is +00:00"); +test("+01:00", "+01:00", "positive offset"); +test("-05:00", "-05:00", "negative offset"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/branding.js new file mode 100644 index 0000000000..404397204f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getOffsetStringFor = Temporal.TimeZone.prototype.getOffsetStringFor; + +assert.sameValue(typeof getOffsetStringFor, "function"); + +const args = [new Temporal.Instant(0n)]; + +assert.throws(TypeError, () => getOffsetStringFor.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getOffsetStringFor.apply(null, args), "null"); +assert.throws(TypeError, () => getOffsetStringFor.apply(true, args), "true"); +assert.throws(TypeError, () => getOffsetStringFor.apply("", args), "empty string"); +assert.throws(TypeError, () => getOffsetStringFor.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getOffsetStringFor.apply(1, args), "1"); +assert.throws(TypeError, () => getOffsetStringFor.apply({}, args), "plain object"); +assert.throws(TypeError, () => getOffsetStringFor.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getOffsetStringFor.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/builtin.js new file mode 100644 index 0000000000..8f21c1bdac --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: > + Tests that Temporal.TimeZone.prototype.getOffsetStringFor + 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.TimeZone.prototype.getOffsetStringFor), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getOffsetStringFor), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getOffsetStringFor), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getOffsetStringFor.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js new file mode 100644 index 0000000000..aa1a319ad6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.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.timezone.prototype.getoffsetstringfor +description: String arguments at the limit of the representable range +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const minInstantStrings = [ + "-271821-04-20T00:00Z", + "-271821-04-19T23:00-01:00", + "-271821-04-19T00:00:00.000000001-23:59:59.999999999", +]; +for (const str of minInstantStrings) { + assert.sameValue(instance.getOffsetStringFor(str), "+00:00", `instant string ${str} should be valid`); +} + +const maxInstantStrings = [ + "+275760-09-13T00:00Z", + "+275760-09-13T01:00+01:00", + "+275760-09-13T23:59:59.999999999+23:59:59.999999999", +]; + +for (const str of maxInstantStrings) { + assert.sameValue(instance.getOffsetStringFor(str), "+00:00", `instant string ${str} should be valid`); +} + +const outOfRangeInstantStrings = [ + "-271821-04-19T23:59:59.999999999Z", + "-271821-04-19T23:00-00:59:59.999999999", + "-271821-04-19T00:00:00-23:59:59.999999999", + "-271821-04-19T00:00:00-24:00", + "+275760-09-13T00:00:00.000000001Z", + "+275760-09-13T01:00+00:59:59.999999999", + "+275760-09-14T00:00+23:59:59.999999999", + "+275760-09-14T00:00+24:00", +]; + +for (const str of outOfRangeInstantStrings) { + assert.throws(RangeError, () => instance.getOffsetStringFor(str), `instant string ${str} should not be valid`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string.js new file mode 100644 index 0000000000..7f24d20313 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +description: Conversion of ISO date-time strings to Temporal.Instant instances +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let str = "1970-01-01T00:00"; +assert.throws(RangeError, () => instance.getOffsetStringFor(str), "bare date-time string is not an instant"); +str = "1970-01-01T00:00[UTC]"; +assert.throws(RangeError, () => instance.getOffsetStringFor(str), "date-time + IANA annotation is not an instant"); + +// The following are all valid strings so should not throw: + +const valids = [ + "1970-01-01T00:00Z", + "1970-01-01T00:00+01:00", + "1970-01-01T00:00Z[UTC]", + "1970-01-01T00:00+01:00[UTC]", + "1970-01-01T00:00Z[u-ca=hebrew]", + "1970-01-01T00:00+01:00[u-ca=hebrew]", + "1970-01-01T00:00+01:00[Etc/Ignored][u-ca=hebrew]", +]; +for (const str of valids) { + const result = instance.getOffsetStringFor(str); + assert.sameValue(result, "+00:00"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/leap-second.js new file mode 100644 index 0000000000..a7eccfdb9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/leap-second.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.timezone.prototype.getoffsetstringfor +description: Leap second is a valid ISO string for Instant +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60Z"; +const result = instance.getOffsetStringFor(arg); +assert.sameValue( + result, + "+00:00", + "leap second is a valid ISO string for Instant" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/length.js new file mode 100644 index 0000000000..459d358ba2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Temporal.TimeZone.prototype.getOffsetStringFor.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.TimeZone.prototype.getOffsetStringFor, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/name.js new file mode 100644 index 0000000000..2d89db3d8b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Temporal.TimeZone.prototype.getOffsetStringFor.name is "getOffsetStringFor". +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.TimeZone.prototype.getOffsetStringFor, "name", { + value: "getOffsetStringFor", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/not-a-constructor.js new file mode 100644 index 0000000000..44e9fbc212 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: > + Temporal.TimeZone.prototype.getOffsetStringFor 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.TimeZone.prototype.getOffsetStringFor(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getOffsetStringFor), false, + "isConstructor(Temporal.TimeZone.prototype.getOffsetStringFor)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/prop-desc.js new file mode 100644 index 0000000000..0e08435c6f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: The "getOffsetStringFor" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getOffsetStringFor, + "function", + "`typeof TimeZone.prototype.getOffsetStringFor` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getOffsetStringFor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..2adc452075 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(RangeError, () => timeZone.getOffsetStringFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..ac0ea2597c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-not-callable.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.timezone.prototype.getoffsetstringfor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => timeZone.getOffsetStringFor(instant), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..3f0d30bc8d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(RangeError, () => timeZone.getOffsetStringFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..0085d63704 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getoffsetstringfor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(TypeError, () => timeZone.getOffsetStringFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/year-zero.js new file mode 100644 index 0000000000..36f2e103e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/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.timezone.prototype.getoffsetstringfor +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-03-30T00:45Z", + "-000000-03-30T01:45+01:00", + "-000000-03-30T01:45:00+00:00[UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getOffsetStringFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-negative-epochnanoseconds.js new file mode 100644 index 0000000000..debcd5957e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-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.timezone.prototype.getplaindatetimefor +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 instant = new Temporal.Instant(-13849764_999_999_999n); + +// 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.TimeZone("UTC"); +const result = instance.getPlainDateTimeFor(instant); +TemporalHelpers.assertPlainDateTime(result, 1969, 7, "M07", 24, 16, 50, 35, 0, 0, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.js new file mode 100644 index 0000000000..6c88ccfadf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.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.timezone.prototype.getplaindatetimefor +description: timeZone.getOffsetNanosecondsFor not called when argument cannot be converted to Temporal.Instant +features: [Temporal] +---*/ + +const timeZone = Temporal.TimeZone.from("UTC"); +let called = false; +timeZone.getOffsetNanosecondsFor = () => called = true; +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(undefined), "undefined"); +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(null), "null"); +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(true), "boolean"); +assert.throws(RangeError, () => timeZone.getPlainDateTimeFor(""), "empty string"); +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(Symbol()), "Symbol"); +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(5), "number"); +assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(5n), "bigint"); +assert.throws(RangeError, () => timeZone.getPlainDateTimeFor({}), "plain object"); +assert.sameValue(called, false); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-object-tostring.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-object-tostring.js new file mode 100644 index 0000000000..371979f3b2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-object-tostring.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.timezone.prototype.getplaindatetimefor +description: Object is converted to a string, then to Temporal.Instant +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = {}; +assert.throws(RangeError, () => instance.getPlainDateTimeFor(arg), "[object Object] is not a valid ISO string"); + +arg.toString = function() { + return "1970-01-01T00:00Z"; +}; +const result = instance.getPlainDateTimeFor(arg); +TemporalHelpers.assertPlainDateTime(result, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "result of toString is interpreted as ISO string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..2e4e0795d1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[u-ca=iso8601]", "without time zone"], + ["1970-01-01T00:00Z[UTC][u-ca=gregory]", "with time zone"], + ["1970-01-01T00:00Z[!u-ca=hebrew]", "with ! and no time zone"], + ["1970-01-01T00:00Z[UTC][!u-ca=chinese]", "with ! and time zone"], + ["1970-01-01T00:00Z[u-ca=discord]", "annotation is ignored"], + ["1970-01-01T00:00Z[!u-ca=discord]", "annotation with ! is ignored"], + ["1970-01-01T00:00Z[u-ca=iso8601][u-ca=discord]", "two annotations are ignored"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPlainDateTimeFor(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..b2af63f79f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar]", + "1970-01-01T00:00Z[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00Z[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..2f5ed3fd9b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const validStrings = [ + "1970-01-01T00Z", + "1970-01-01T00Z[UTC]", + "1970-01-01T00Z[!UTC]", + "1970-01-01T00Z[Europe/Vienna]", + "1970-01-01T00+00:00", + "1970-01-01T00+00:00[UTC]", + "1970-01-01T00+00:00[!UTC]", + "1969-12-31T16-08:00[America/Vancouver]", +]; + +for (const arg of validStrings) { + const result = instance.getPlainDateTimeFor(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, + `"${arg}" is a valid UTC offset with time for Instant` + ); +} + +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.getPlainDateTimeFor(arg), + `"${arg}" UTC offset without time is not valid for Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-invalid.js new file mode 100644 index 0000000000..940de774cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as an Instant +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00T00:00Z", + "2020-01-32T00:00Z", + "2020-02-30T00:00Z", + "2021-02-29T00:00Z", + "2020-00-01T00:00Z", + "2020-13-01T00:00Z", + "2020-01-01TZ", + "2020-01-01T25:00:00Z", + "2020-01-01T01:60:00Z", + "2020-01-01T01:60:61Z", + "2020-01-01T00:00Zjunk", + "2020-01-01T00:00:00Zjunk", + "2020-01-01T00:00:00.000000000Zjunk", + "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-01T00:00Z", + "2020-001-01T00:00Z", + "2020-01-001T00:00Z", + "2020-01-01T001Z", + "2020-01-01T01:001Z", + "2020-01-01T01:01:001Z", + // valid, but forms not supported in Temporal: + "2020-W01-1T00:00Z", + "2020-001T00:00Z", + "+0002020-01-01T00:00Z", + // may be valid in other contexts, but insufficient information for Instant: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + "2020-01-01", + "2020-01-01T00", + "2020-01-01T00:00", + "2020-01-01T00:00:00", + "2020-01-01T00:00:00.000000000", + // valid, but outside the supported range: + "-999999-01-01T00:00Z", + "+999999-01-01T00:00Z", +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(arg), + `"${arg}" should not be a valid ISO string for an Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..795d9d0314 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-calendar.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.timezone.prototype.getplaindatetimefor +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..6738c47956 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[UTC][UTC]", + "1970-01-01T00:00Z[!UTC][UTC]", + "1970-01-01T00:00Z[UTC][!UTC]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00Z[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-time-separators.js new file mode 100644 index 0000000000..ea443c1a3c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Time separator in string argument can vary +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1970-01-01T00:00Z", "uppercase T"], + ["1970-01-01t00:00Z", "lowercase T"], + ["1970-01-01 00:00Z", "space between date and time"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPlainDateTimeFor(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..15a4408df4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[Asia/Kolkata]", "named, with Z"], + ["1970-01-01T00:00Z[!Europe/Vienna]", "named, with Z and !"], + ["1970-01-01T00:00Z[+00:00]", "numeric, with Z"], + ["1970-01-01T00:00Z[!-02:30]", "numeric, with Z and !"], + ["1970-01-01T00:00+00:00[UTC]", "named, with offset"], + ["1970-01-01T00:00+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1970-01-01T00:00+00:00[-08:00]", "numeric, with offset"], + ["1970-01-01T00:00+00:00[!+01:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPlainDateTimeFor(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..bf73224e68 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Various forms of unknown annotation +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[foo=bar]", "alone"], + ["1970-01-01T00:00Z[UTC][foo=bar]", "with time zone"], + ["1970-01-01T00:00Z[u-ca=iso8601][foo=bar]", "with calendar"], + ["1970-01-01T00:00Z[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1970-01-01T00:00Z[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPlainDateTimeFor(arg); + + TemporalHelpers.assertPlainDateTime( + result, + 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type.js new file mode 100644 index 0000000000..b6c9d6ccb0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-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.timezone.prototype.getplaindatetimefor +description: > + Appropriate error thrown when argument cannot be converted to a valid string + for Instant +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const primitiveTests = [ + [undefined, "undefined"], + [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"], + [{}, "plain object"], + [Temporal.Instant, "Temporal.Instant, object"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === "string" || (typeof arg === "object" && arg !== null) || typeof arg === "function" + ? RangeError + : TypeError, + () => instance.getPlainDateTimeFor(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [Temporal.Instant.prototype, "Temporal.Instant.prototype, object"], // fails brand check in toString() +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.getPlainDateTimeFor(arg), `${description} does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.js new file mode 100644 index 0000000000..b25c280c9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.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.timezone.prototype.getplaindatetimefor +description: Fast path for converting Temporal.ZonedDateTime to Temporal.Instant +info: | + sec-temporal.timezone.prototype.getplaindatetimefor step 2: + 2. Set _instant_ to ? ToTemporalInstant(_instant_). + sec-temporal-totemporalinstant step 1.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return ! CreateTemporalInstant(_item_.[[Nanoseconds]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalInstantFastPath((datetime) => { + const timeZone = Temporal.TimeZone.from("UTC"); + const result = timeZone.getPlainDateTimeFor(datetime); + TemporalHelpers.assertPlainDateTime(result, 2001, 9, "M09", 9, 1, 46, 40, 987, 654, 321); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/balance-negative-time-units.js new file mode 100644 index 0000000000..12587c4260 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/balance-negative-time-units.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +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-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-get-temporal.timezone.prototype.getplaindatetimefor step 4: + 4. Return ? BuiltinTimeZoneGetPlainDateTimeFor(_timeZone_, _instant_, _calendar_). +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 instant = new Temporal.Instant(1001n); + +const pdt = tz.getPlainDateTimeFor(instant); + +TemporalHelpers.assertPlainDateTime(pdt, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 999); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/branding.js new file mode 100644 index 0000000000..f3f7eccc9c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getPlainDateTimeFor = Temporal.TimeZone.prototype.getPlainDateTimeFor; + +assert.sameValue(typeof getPlainDateTimeFor, "function"); + +const args = [new Temporal.Instant(0n)]; + +assert.throws(TypeError, () => getPlainDateTimeFor.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(null, args), "null"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(true, args), "true"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply("", args), "empty string"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(1, args), "1"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply({}, args), "plain object"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getPlainDateTimeFor.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/builtin.js new file mode 100644 index 0000000000..efcbeaf959 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: > + Tests that Temporal.TimeZone.prototype.getPlainDateTimeFor + 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.TimeZone.prototype.getPlainDateTimeFor), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getPlainDateTimeFor), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getPlainDateTimeFor), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getPlainDateTimeFor.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-case-insensitive.js new file mode 100644 index 0000000000..fdfa4a39ba --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-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.timezone.prototype.getplaindatetimefor +description: Calendar names are case-insensitive +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "iSo8601"; +const result = instance.getPlainDateTimeFor(new Temporal.Instant(0n), arg); +assert.sameValue(result.calendarId, "iso8601", "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-number.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-number.js new file mode 100644 index 0000000000..0cf2bc2a3b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: A number is not allowed to be a calendar +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const numbers = [ + 1, + -19761118, + 19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.getPlainDateTimeFor(new Temporal.Instant(0n), arg), + "A number is not a valid ISO string for Calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-string-leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-string-leap-second.js new file mode 100644 index 0000000000..9b3aeeb9d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-string-leap-second.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.timezone.prototype.getplaindatetimefor +description: Leap second is a valid ISO string for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60"; +const result = instance.getPlainDateTimeFor(new Temporal.Instant(0n), 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/TimeZone/prototype/getPlainDateTimeFor/calendar-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-string.js new file mode 100644 index 0000000000..eb154757a6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-string.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.timezone.prototype.getplaindatetimefor +description: A calendar ID is valid input for Calendar +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "iso8601"; + +const result = instance.getPlainDateTimeFor(new Temporal.Instant(0n), 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/TimeZone/prototype/getPlainDateTimeFor/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-temporal-object.js new file mode 100644 index 0000000000..295ea57cfb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-temporal-object.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +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.TimeZone("UTC"); + const result = instance.getPlainDateTimeFor(new Temporal.Instant(0n), 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/TimeZone/prototype/getPlainDateTimeFor/calendar-undefined.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-undefined.js new file mode 100644 index 0000000000..6041c710d6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-undefined.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +description: Calendar argument defaults to the built-in ISO 8601 calendar +features: [Temporal] +---*/ + +const instant = Temporal.Instant.from("1975-02-02T14:25:36.123456789Z"); +const timeZone = Temporal.TimeZone.from("UTC"); + +Object.defineProperty(Temporal.Calendar, "from", { + get() { + throw new Test262Error("Should not call Calendar.from"); + }, +}); + +const result1 = timeZone.getPlainDateTimeFor(instant); +assert.sameValue(result1.calendarId, "iso8601"); + +const result2 = timeZone.getPlainDateTimeFor(instant, undefined); +assert.sameValue(result2.calendarId, "iso8601"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-wrong-type.js new file mode 100644 index 0000000000..9998c731b9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-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.timezone.prototype.getplaindatetimefor +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.TimeZone("UTC"); + +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.getPlainDateTimeFor(new Temporal.Instant(0n), 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.getPlainDateTimeFor(new Temporal.Instant(0n), 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/TimeZone/prototype/getPlainDateTimeFor/custom-timezone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/custom-timezone.js new file mode 100644 index 0000000000..b7844462a5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/custom-timezone.js @@ -0,0 +1,30 @@ +// |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.timezone.prototype.getplaindatetimefor +description: getOffsetNanosecondsFor is called by getPlainDateTimeFor +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + "get getOffsetNanosecondsFor", + "call timeZone.getOffsetNanosecondsFor", +]; + +const instant = Temporal.Instant.from("1975-02-02T14:25:36.123456789Z"); +const timeZone = new Temporal.TimeZone("UTC"); +TemporalHelpers.observeProperty(actual, timeZone, "getOffsetNanosecondsFor", function (instantArg) { + actual.push("call timeZone.getOffsetNanosecondsFor"); + assert.sameValue(instantArg, instant); + return 9876543210123; +}); + +const result = timeZone.getPlainDateTimeFor(instant); +TemporalHelpers.assertPlainDateTime(result, 1975, 2, "M02", 2, 17, 10, 12, 666, 666, 912); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js new file mode 100644 index 0000000000..e57fef37f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.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.timezone.prototype.getplaindatetimefor +description: String arguments at the limit of the representable range +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const minInstantStrings = [ + "-271821-04-20T00:00Z", + "-271821-04-19T23:00-01:00", + "-271821-04-19T00:00:00.000000001-23:59:59.999999999", +]; +for (const str of minInstantStrings) { + TemporalHelpers.assertPlainDateTime(instance.getPlainDateTimeFor(str), -271821, 4, "M04", 20, 0, 0, 0, 0, 0, 0, `instant string ${str} should be valid`); +} + +const maxInstantStrings = [ + "+275760-09-13T00:00Z", + "+275760-09-13T01:00+01:00", + "+275760-09-13T23:59:59.999999999+23:59:59.999999999", +]; + +for (const str of maxInstantStrings) { + TemporalHelpers.assertPlainDateTime(instance.getPlainDateTimeFor(str), 275760, 9, "M09", 13, 0, 0, 0, 0, 0, 0, `instant string ${str} should be valid`); +} + +const outOfRangeInstantStrings = [ + "-271821-04-19T23:59:59.999999999Z", + "-271821-04-19T23:00-00:59:59.999999999", + "-271821-04-19T00:00:00-23:59:59.999999999", + "-271821-04-19T00:00:00-24:00", + "+275760-09-13T00:00:00.000000001Z", + "+275760-09-13T01:00+00:59:59.999999999", + "+275760-09-14T00:00+23:59:59.999999999", + "+275760-09-14T00:00+24:00", +]; + +for (const str of outOfRangeInstantStrings) { + assert.throws(RangeError, () => instance.getPlainDateTimeFor(str), `instant string ${str} should not be valid`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-multiple-offsets.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-multiple-offsets.js new file mode 100644 index 0000000000..b4a9db98e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-multiple-offsets.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.timezone.prototype.getplaindatetimefor +description: Instant strings with UTC offset fractional part are not confused with time fractional part +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); +const str = "1970-01-01T00:02:00.000000000+00:02[+01:30]"; + +const result = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "UTC offset determined from offset part of string"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-sub-minute-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-sub-minute-offset.js new file mode 100644 index 0000000000..3e1cf18982 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-sub-minute-offset.js @@ -0,0 +1,68 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +description: Temporal.Instant string with sub-minute offset +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const str = "1970-01-01T00:19:32.37+00:19:32.37"; +const result = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "if present, sub-minute offset is accepted exactly"); + +[ + "2021-08-19T17:30-07:00:01[-07:00:01]", + "2021-08-19T17:30-07:00:00[-07:00:00]", + "2021-08-19T17:30-07:00:00.1[-07:00:00.1]", + "2021-08-19T17:30-07:00:00.0[-07:00:00.0]", + "2021-08-19T17:30-07:00:00.01[-07:00:00.01]", + "2021-08-19T17:30-07:00:00.00[-07:00:00.00]", + "2021-08-19T17:30-07:00:00.001[-07:00:00.001]", + "2021-08-19T17:30-07:00:00.000[-07:00:00.000]", + "2021-08-19T17:30-07:00:00.0001[-07:00:00.0001]", + "2021-08-19T17:30-07:00:00.0000[-07:00:00.0000]", + "2021-08-19T17:30-07:00:00.00001[-07:00:00.00001]", + "2021-08-19T17:30-07:00:00.00000[-07:00:00.00000]", + "2021-08-19T17:30-07:00:00.000001[-07:00:00.000001]", + "2021-08-19T17:30-07:00:00.000000[-07:00:00.000000]", + "2021-08-19T17:30-07:00:00.0000001[-07:00:00.0000001]", + "2021-08-19T17:30-07:00:00.0000000[-07:00:00.0000000]", + "2021-08-19T17:30-07:00:00.00000001[-07:00:00.00000001]", + "2021-08-19T17:30-07:00:00.00000000[-07:00:00.00000000]", + "2021-08-19T17:30-07:00:00.000000001[-07:00:00.000000001]", + "2021-08-19T17:30-07:00:00.000000000[-07:00:00.000000000]", + + "2021-08-19T17:30-07:00:01[-070001]", + "2021-08-19T17:30-07:00:00[-070000]", + "2021-08-19T17:30-07:00:00.1[-070000.1]", + "2021-08-19T17:30-07:00:00.0[-070000.0]", + "2021-08-19T17:30-07:00:00.01[-070000.01]", + "2021-08-19T17:30-07:00:00.00[-070000.00]", + "2021-08-19T17:30-07:00:00.001[-070000.001]", + "2021-08-19T17:30-07:00:00.000[-070000.000]", + "2021-08-19T17:30-07:00:00.0001[-070000.0001]", + "2021-08-19T17:30-07:00:00.0000[-070000.0000]", + "2021-08-19T17:30-07:00:00.00001[-070000.00001]", + "2021-08-19T17:30-07:00:00.00000[-070000.00000]", + "2021-08-19T17:30-07:00:00.000001[-070000.000001]", + "2021-08-19T17:30-07:00:00.000000[-070000.000000]", + "2021-08-19T17:30-07:00:00.0000001[-070000.0000001]", + "2021-08-19T17:30-07:00:00.0000000[-070000.0000000]", + "2021-08-19T17:30-07:00:00.00000001[-070000.00000001]", + "2021-08-19T17:30-07:00:00.00000000[-070000.00000000]", + "2021-08-19T17:30-07:00:00.000000001[-070000.000000001]", + "2021-08-19T17:30-07:00:00.000000000[-070000.000000000]" +].forEach((str) => { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(str), + `ISO strings cannot have sub-minute offsets in time zone annotations: ${str}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string.js new file mode 100644 index 0000000000..3f1abf2108 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string.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.timezone.prototype.getplaindatetimefor +description: Conversion of ISO date-time strings to Temporal.Instant instances +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let str = "1970-01-01T00:00"; +assert.throws(RangeError, () => instance.getPlainDateTimeFor(str), "bare date-time string is not an instant"); +str = "1970-01-01T00:00[UTC]"; +assert.throws(RangeError, () => instance.getPlainDateTimeFor(str), "date-time + IANA annotation is not an instant"); + +str = "1970-01-01T00:00Z"; +const result1 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result1, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "date-time + Z preserves exact time"); + +str = "1970-01-01T00:00+01:00"; +const result2 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result2, 1969, 12, "M12", 31, 23, 0, 0, 0, 0, 0, "date-time + offset preserves exact time with offset"); + +str = "1970-01-01T00:00Z[Etc/Ignored]"; +const result3 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result3, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "date-time + Z + IANA annotation ignores the IANA annotation"); + +str = "1970-01-01T00:00+01:00[Etc/Ignored]"; +const result4 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result4, 1969, 12, "M12", 31, 23, 0, 0, 0, 0, 0, "date-time + offset + IANA annotation ignores the IANA annotation"); + +str = "1970-01-01T00:00Z[u-ca=hebrew]"; +const result6 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result6, 1970, 1, "M01", 1, 0, 0, 0, 0, 0, 0, "date-time + Z + Calendar ignores the Calendar"); + +str = "1970-01-01T00:00+01:00[u-ca=hebrew]"; +const result5 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result5, 1969, 12, "M12", 31, 23, 0, 0, 0, 0, 0, "date-time + offset + Calendar ignores the Calendar"); + +str = "1970-01-01T00:00+01:00[Etc/Ignored][u-ca=hebrew]"; +const result7 = instance.getPlainDateTimeFor(str); +TemporalHelpers.assertPlainDateTime(result7, 1969, 12, "M12", 31, 23, 0, 0, 0, 0, 0, "date-time + offset + IANA annotation + Calendar ignores the Calendar and IANA annotation"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/leap-second.js new file mode 100644 index 0000000000..446e96c161 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/leap-second.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +description: Leap second is a valid ISO string for Instant +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60Z"; +const result = instance.getPlainDateTimeFor(arg); +TemporalHelpers.assertPlainDateTime( + result, + 2016, 12, "M12", 31, 23, 59, 59, 0, 0, 0, + "leap second is a valid ISO string for Instant" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/length.js new file mode 100644 index 0000000000..b3021c4bc7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Temporal.TimeZone.prototype.getPlainDateTimeFor.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.TimeZone.prototype.getPlainDateTimeFor, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/limits.js new file mode 100644 index 0000000000..f4cf0af7af --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/limits.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.getplaindatetimefor +description: Checking limits of representable PlainDateTime +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +const min = new Temporal.Instant(-8_640_000_000_000_000_000_000n); +const offsetMin = new Temporal.TimeZone("-23:59"); +const max = new Temporal.Instant(8_640_000_000_000_000_000_000n); +const offsetMax = new Temporal.TimeZone("+23:59"); + +TemporalHelpers.assertPlainDateTime( + offsetMin.getPlainDateTimeFor(min, "iso8601"), + -271821, 4, "M04", 19, 0, 1, 0, 0, 0, 0, + "converting from Instant (negative case)" +); + +TemporalHelpers.assertPlainDateTime( + offsetMax.getPlainDateTimeFor(max, "iso8601"), + 275760, 9, "M09", 13, 23, 59, 0, 0, 0, 0, + "converting from Instant (positive case)" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/name.js new file mode 100644 index 0000000000..abf3dbe263 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Temporal.TimeZone.prototype.getPlainDateTimeFor.name is "getPlainDateTimeFor". +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.TimeZone.prototype.getPlainDateTimeFor, "name", { + value: "getPlainDateTimeFor", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/not-a-constructor.js new file mode 100644 index 0000000000..2d75ed6e0f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: > + Temporal.TimeZone.prototype.getPlainDateTimeFor 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.TimeZone.prototype.getPlainDateTimeFor(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getPlainDateTimeFor), false, + "isConstructor(Temporal.TimeZone.prototype.getPlainDateTimeFor)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/pre-epoch.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/pre-epoch.js new file mode 100644 index 0000000000..97cd406175 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/pre-epoch.js @@ -0,0 +1,18 @@ +// |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.timezone.prototype.getplaindatetimefor +description: Test of basic functionality for an exact time earlier than the Unix epoch +includes: [temporalHelpers.js] +features: [Temporal] +---*/ + +const instant = Temporal.Instant.from("1969-07-16T13:32:01.234567891Z"); +assert.sameValue(instant.toString(), "1969-07-16T13:32:01.234567891Z"); +const timeZone = Temporal.TimeZone.from("-04:00"); +const dateTime = timeZone.getPlainDateTimeFor(instant); +TemporalHelpers.assertPlainDateTime(dateTime, 1969, 7, "M07", 16, 9, 32, 1, 234, 567, 891); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/prop-desc.js new file mode 100644 index 0000000000..b7ec44a682 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: The "getPlainDateTimeFor" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getPlainDateTimeFor, + "function", + "`typeof TimeZone.prototype.getPlainDateTimeFor` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getPlainDateTimeFor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..29518fb241 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(RangeError, () => timeZone.getPlainDateTimeFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..f3608d2f51 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-not-callable.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.timezone.prototype.getplaindatetimefor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => timeZone.getPlainDateTimeFor(instant), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..56ce2f31e6 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(RangeError, () => timeZone.getPlainDateTimeFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..1976e19cd0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getplaindatetimefor +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 instant = new Temporal.Instant(1_000_000_000_987_654_321n); + assert.throws(TypeError, () => timeZone.getPlainDateTimeFor(instant)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/year-zero.js new file mode 100644 index 0000000000..56c08eb631 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/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.timezone.prototype.getplaindatetimefor +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-03-30T00:45Z", + "-000000-03-30T01:45+01:00", + "-000000-03-30T01:45:00+00:00[UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPlainDateTimeFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-builtin-calendar-no-array-iteration.js new file mode 100644 index 0000000000..13b01796cb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +const arg = { year: 2000, month: 5, day: 2, hour: 21, minute: 43, second: 5, calendar: "iso8601" }; +instance.getPossibleInstantsFor(arg); + +Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js new file mode 100644 index 0000000000..6886ee6617 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js @@ -0,0 +1,21 @@ +// |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.timezone.prototype.getpossibleinstantsfor +description: Appropriate error thrown when argument cannot be converted to Temporal.PlainDateTime +features: [Temporal] +---*/ + +const timeZone = Temporal.TimeZone.from("UTC"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(undefined), "undefined"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(null), "null"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(true), "boolean"); +assert.throws(RangeError, () => timeZone.getPossibleInstantsFor(""), "empty string"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(Symbol()), "Symbol"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(5), "number"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor(5n), "bigint"); +assert.throws(TypeError, () => timeZone.getPossibleInstantsFor({}), "plain object"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-number.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-number.js new file mode 100644 index 0000000000..a0002e932b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: A number cannot be used in place of a Temporal.PlainDateTime +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const numbers = [ + 1, + 19761118, + -19761118, + 1234567890, +]; + +for (const arg of numbers) { + assert.throws( + TypeError, + () => instance.getPossibleInstantsFor(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/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.js new file mode 100644 index 0000000000..967fdf7454 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.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.until +description: Fast path for converting Temporal.PlainDate to Temporal.PlainDateTime by reading internal slots +info: | + sec-temporal.timezone.prototype.getpossibleinstantsfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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) => { + const timezone = new Temporal.TimeZone("UTC"); + const result = timezone.getPossibleInstantsFor(date); + assert.sameValue(result.length, 1, "one possible instant"); + assert.sameValue(result[0].epochNanoseconds, 957_225_600_000_000_000n, "epochNanoseconds result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-case-insensitive.js new file mode 100644 index 0000000000..b83394a8e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: The calendar name is case-insensitive +includes: [compareArray.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "IsO8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getPossibleInstantsFor(arg); +assert.compareArray(result.map(i => i.epochNanoseconds), [217_123_200_000_000_000n], "Calendar is case-insensitive"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-leap-second.js new file mode 100644 index 0000000000..9c4175f5da --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Leap second is a valid ISO string for a calendar in a property bag +includes: [compareArray.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "2016-12-31T23:59:60"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getPossibleInstantsFor(arg); +assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_123_200_000_000_000n], + "leap second is a valid ISO string for calendar" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-number.js new file mode 100644 index 0000000000..c677cdf355 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: A number as calendar in a property bag is not accepted +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const numbers = [ + 1, + 19970327, + -19970327, + 1234567890, +]; + +for (const calendar of numbers) { + const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; + assert.throws( + TypeError, + () => instance.getPossibleInstantsFor(arg), + "Numbers cannot be used as a calendar" + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-string.js new file mode 100644 index 0000000000..bcccdb578c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: A calendar ID is valid input for Calendar +includes: [compareArray.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const calendar = "iso8601"; + +const arg = { year: 1976, monthCode: "M11", day: 18, calendar }; +const result = instance.getPossibleInstantsFor(arg); +assert.compareArray(result.map(i => i.epochNanoseconds), [217_123_200_000_000_000n], `Calendar created from string "${calendar}"`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-wrong-type.js new file mode 100644 index 0000000000..9bb67c587e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); + +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.getPossibleInstantsFor(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.getPossibleInstantsFor(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/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-year-zero.js new file mode 100644 index 0000000000..0afcf6f978 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..ccc8eb6447 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +includes: [compareArray.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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPossibleInstantsFor(arg); + + assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_178_580_000_000_000n], + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..d0d4f3bb3d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..a6a045e438 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: UTC offset not valid with format that does not include a time +features: [Temporal] +includes: [compareArray.js] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +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.getPossibleInstantsFor(arg); + + assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_178_580_000_000_000n], + `"${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.getPossibleInstantsFor(arg), + `"${arg}" UTC offset without time is not valid for PlainDateTime` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..b29552e4c7 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..8d8944fe22 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-time-separators.js new file mode 100644 index 0000000000..d25d8923d1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Time separator in string argument can vary +features: [Temporal] +includes: [compareArray.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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPossibleInstantsFor(arg); + + assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_178_580_000_000_000n], + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..eba484f410 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +includes: [compareArray.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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPossibleInstantsFor(arg); + + assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_178_580_000_000_000n], + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..df1811ea08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Various forms of unknown annotation +features: [Temporal] +includes: [compareArray.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.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPossibleInstantsFor(arg); + + assert.compareArray( + result.map(i => i.epochNanoseconds), + [217_178_580_000_000_000n], + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-with-utc-designator.js new file mode 100644 index 0000000000..11ee17ba4e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(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/TimeZone/prototype/getPossibleInstantsFor/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-wrong-type.js new file mode 100644 index 0000000000..697d95c314 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); + +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.getPossibleInstantsFor(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.getPossibleInstantsFor(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/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-balance-negative-time-units.js new file mode 100644 index 0000000000..62e3cd227c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-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.timezone.prototype.getpossibleinstantsfor +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.timezone.prototype.getpossibleinstantsfor step 3: + 3. Set _dateTime_ ? ToTemporalDateTime(_dateTime_). +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 conversionTimeZone = new Temporal.TimeZone("UTC"); // should not be used to interpret the argument +const instants = conversionTimeZone.getPossibleInstantsFor(datetime); + +assert.sameValue(instants.length, 1); +assert.sameValue(instants[0].epochNanoseconds, 3661_001_000_999n); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-negative-epochnanoseconds.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-negative-epochnanoseconds.js new file mode 100644 index 0000000000..765b0c7115 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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: [compareArray.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.TimeZone("UTC"); +const result = instance.getPossibleInstantsFor(datetime); +assert.compareArray(result.map((i) => i.epochNanoseconds), [-13849764_999_999_999n]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..10dabb1e8e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(RangeError, () => builtinTimeZone.getPossibleInstantsFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js new file mode 100644 index 0000000000..3326adae54 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable +features: [BigInt, Symbol, Temporal, arrow-function] +---*/ + +[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => { + const timeZone = new Temporal.TimeZone("UTC"); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + timeZone.getOffsetNanosecondsFor = notCallable; + assert.throws( + TypeError, + () => builtinTimeZone.getPossibleInstantsFor(datetime), + `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..e84e4bb835 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(RangeError, () => builtinTimeZone.getPossibleInstantsFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..b892868072 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: TypeError thrown if time zone reports an offset that is not a Number +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[ + undefined, + null, + true, + "+01:00", + Symbol(), + 3600_000_000_000n, + {}, + { valueOf() { return 3600_000_000_000; } }, +].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + const builtinTimeZone = new Temporal.TimeZone("UTC"); + assert.throws(TypeError, () => builtinTimeZone.getPossibleInstantsFor(datetime)); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/branding.js new file mode 100644 index 0000000000..28112ebb0b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getPossibleInstantsFor = Temporal.TimeZone.prototype.getPossibleInstantsFor; + +assert.sameValue(typeof getPossibleInstantsFor, "function"); + +const args = [new Temporal.PlainDateTime(2022, 6, 22)]; + +assert.throws(TypeError, () => getPossibleInstantsFor.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(null, args), "null"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(true, args), "true"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply("", args), "empty string"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(1, args), "1"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply({}, args), "plain object"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getPossibleInstantsFor.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/builtin.js new file mode 100644 index 0000000000..2b19200aef --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: > + Tests that Temporal.TimeZone.prototype.getPossibleInstantsFor + 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.TimeZone.prototype.getPossibleInstantsFor), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getPossibleInstantsFor), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getPossibleInstantsFor), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getPossibleInstantsFor.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-datefromfields-called-with-null-prototype-fields.js new file mode 100644 index 0000000000..97dcbe9239 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +const arg = { year: 2000, month: 5, day: 2, calendar }; +instance.getPossibleInstantsFor(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/TimeZone/prototype/getPossibleInstantsFor/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-fields-iterable.js new file mode 100644 index 0000000000..ecbfbceb69 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-fields-iterable.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.timezone.prototype.getpossibleinstantsfor +description: Verify the result of calendar.fields() is treated correctly. +info: | + sec-temporal.timezone.prototype.getpossibleinstantsfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 calendar = TemporalHelpers.calendarFieldsIterable(); +const timeZone = new Temporal.TimeZone("UTC"); +timeZone.getPossibleInstantsFor({ year: 2000, month: 5, day: 2, calendar }); + +assert.sameValue(calendar.fieldsCallCount, 1, "fields() method called once"); +assert.compareArray(calendar.fieldsCalledWith[0], expected, "fields() method called with correct args"); +assert(calendar.iteratorExhausted[0], "iterated through the whole iterable"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-temporal-object.js new file mode 100644 index 0000000000..32b8613628 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.timezone.prototype.getpossibleinstantsfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 timeZone = new Temporal.TimeZone("UTC"); + timeZone.getPossibleInstantsFor({ year: 2000, month: 5, day: 2, calendar: temporalObject }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/constructor-in-calendar-fields.js new file mode 100644 index 0000000000..245f90b226 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); + +assert.throws(RangeError, () => instance.getPossibleInstantsFor(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/duplicate-calendar-fields.js new file mode 100644 index 0000000000..30d79e324c --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); + + assert.throws(RangeError, () => instance.getPossibleInstantsFor(arg)); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/fixed-offset-near-date-time-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/fixed-offset-near-date-time-limits.js new file mode 100644 index 0000000000..bf70291dc9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/fixed-offset-near-date-time-limits.js @@ -0,0 +1,57 @@ +// |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.timezone.prototype.getpossibleinstantsfor +description: > + Call getPossibleInstantsFor with values near the date/time limit and a fixed offset. +features: [Temporal, exponentiation] +---*/ + +const oneHour = 1n * 60n * 60n * 1000n**3n; + +const minDt = new Temporal.PlainDateTime(-271821, 4, 19, 1, 0, 0, 0, 0, 0); +const minValidDt = new Temporal.PlainDateTime(-271821, 4, 20, 0, 0, 0, 0, 0, 0); +const maxDt = new Temporal.PlainDateTime(275760, 9, 13, 0, 0, 0, 0, 0, 0); + +let zero = new Temporal.TimeZone("+00"); +let plusOne = new Temporal.TimeZone("+01"); +let minusOne = new Temporal.TimeZone("-01"); + +// Try the minimum date-time. +assert.throws(RangeError, () => zero.getPossibleInstantsFor(minDt)); +assert.throws(RangeError, () => plusOne.getPossibleInstantsFor(minDt)); +assert.throws(RangeError, () => minusOne.getPossibleInstantsFor(minDt)); + +// Try the minimum valid date-time. +{ + let r = zero.getPossibleInstantsFor(minValidDt); + assert.sameValue(r.length, 1); + assert.sameValue(r[0].epochNanoseconds, -86_40000_00000_00000_00000n); +} + +{ + let r = minusOne.getPossibleInstantsFor(minValidDt); + assert.sameValue(r.length, 1); + assert.sameValue(r[0].epochNanoseconds, -86_40000_00000_00000_00000n + oneHour); +} + +assert.throws(RangeError, () => plusOne.getPossibleInstantsFor(minValidDt)); + +// Try the maximum valid date-time. +{ + let r = zero.getPossibleInstantsFor(maxDt); + assert.sameValue(r.length, 1); + assert.sameValue(r[0].epochNanoseconds, 86_40000_00000_00000_00000n); +} + +{ + let r = plusOne.getPossibleInstantsFor(maxDt); + assert.sameValue(r.length, 1); + assert.sameValue(r[0].epochNanoseconds, 86_40000_00000_00000_00000n - oneHour); +} + +assert.throws(RangeError, () => minusOne.getPossibleInstantsFor(maxDt)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/infinity-throws-rangeerror.js new file mode 100644 index 0000000000..d40ebce61e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); +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.getPossibleInstantsFor({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`); + + const calls = []; + const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop); + assert.throws(RangeError, () => instance.getPossibleInstantsFor({ ...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/TimeZone/prototype/getPossibleInstantsFor/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/leap-second.js new file mode 100644 index 0000000000..6b96daa289 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Leap second is a valid ISO string for PlainDateTime +includes: [compareArray.js] +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let arg = "2016-12-31T23:59:60"; +const result1 = instance.getPossibleInstantsFor(arg); +assert.compareArray( + result1.map(i => i.epochNanoseconds), + [1_483_228_799_000_000_000n], + "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.getPossibleInstantsFor(arg); +assert.compareArray( + result2.map(i => i.epochNanoseconds), + [1_483_228_799_000_000_000n], + "second: 60 is ignored in property bag for PlainDateTime" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/length.js new file mode 100644 index 0000000000..cc04a14788 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Temporal.TimeZone.prototype.getPossibleInstantsFor.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.TimeZone.prototype.getPossibleInstantsFor, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/name.js new file mode 100644 index 0000000000..f5713a2e80 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: Temporal.TimeZone.prototype.getPossibleInstantsFor.name is "getPossibleInstantsFor". +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.TimeZone.prototype.getPossibleInstantsFor, "name", { + value: "getPossibleInstantsFor", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/not-a-constructor.js new file mode 100644 index 0000000000..14789fdf50 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: > + Temporal.TimeZone.prototype.getPossibleInstantsFor 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.TimeZone.prototype.getPossibleInstantsFor(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getPossibleInstantsFor), false, + "isConstructor(Temporal.TimeZone.prototype.getPossibleInstantsFor)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/prop-desc.js new file mode 100644 index 0000000000..aeb6aa976e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +description: The "getPossibleInstantsFor" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getPossibleInstantsFor, + "function", + "`typeof TimeZone.prototype.getPossibleInstantsFor` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getPossibleInstantsFor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/proto-in-calendar-fields.js new file mode 100644 index 0000000000..09aeb655a2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); + +assert.throws(RangeError, () => instance.getPossibleInstantsFor(arg)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/read-time-fields-before-datefromfields.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/read-time-fields-before-datefromfields.js new file mode 100644 index 0000000000..e75ccfd8cf --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/read-time-fields-before-datefromfields.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.timezone.prototype.getpossibleinstantsfor +description: The time fields are read from the object before being passed to dateFromFields(). +info: | + sec-temporal.timezone.prototype.getpossibleinstantsfor step 3: + 3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_). + 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 timezone = new Temporal.TimeZone("UTC"); +const calendar = TemporalHelpers.calendarMakeInfinityTime(); +const result = timezone.getPossibleInstantsFor({ year: 1970, month: 1, day: 1, calendar }); + +assert.sameValue(result.length, 1, "result array length"); +assert.sameValue(result[0].epochNanoseconds, 0n, "epochNanoseconds result"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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/TimeZone/prototype/getPossibleInstantsFor/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/year-zero.js new file mode 100644 index 0000000000..fa4c15dce1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/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.timezone.prototype.getpossibleinstantsfor +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.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPossibleInstantsFor(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js new file mode 100644 index 0000000000..b8867e8b6a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getprevioustransition +description: Various forms of calendar annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[u-ca=iso8601]", "without time zone"], + ["1970-01-01T00:00Z[UTC][u-ca=gregory]", "with time zone"], + ["1970-01-01T00:00Z[!u-ca=hebrew]", "with ! and no time zone"], + ["1970-01-01T00:00Z[UTC][!u-ca=chinese]", "with ! and time zone"], + ["1970-01-01T00:00Z[u-ca=discord]", "annotation is ignored"], + ["1970-01-01T00:00Z[!u-ca=discord]", "annotation with ! is ignored"], + ["1970-01-01T00:00Z[u-ca=iso8601][u-ca=discord]", "two annotations are ignored"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPreviousTransition(arg); + + assert.sameValue( + result, + null, + `calendar annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-critical-unknown-annotation.js new file mode 100644 index 0000000000..7476dd322d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Unknown annotations with critical flag are rejected +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar]", + "1970-01-01T00:00Z[u-ca=iso8601][!foo=bar]", + "1970-01-01T00:00Z[UTC][!foo=bar][u-ca=iso8601]", + "1970-01-01T00:00Z[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPreviousTransition(arg), + `reject unknown annotation with critical flag: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js new file mode 100644 index 0000000000..f8c6ed644e --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getprevioustransition +description: UTC offset not valid with format that does not include a time +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const validStrings = [ + "1970-01-01T00Z", + "1970-01-01T00Z[UTC]", + "1970-01-01T00Z[!UTC]", + "1970-01-01T00Z[Europe/Vienna]", + "1970-01-01T00+00:00", + "1970-01-01T00+00:00[UTC]", + "1970-01-01T00+00:00[!UTC]", + "1969-12-31T16-08:00[America/Vancouver]", +]; + +for (const arg of validStrings) { + const result = instance.getPreviousTransition(arg); + + assert.sameValue( + result, + null, + `"${arg}" is a valid UTC offset with time for Instant` + ); +} + +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.getPreviousTransition(arg), + `"${arg}" UTC offset without time is not valid for Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-invalid.js new file mode 100644 index 0000000000..56b970b203 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-invalid.js @@ -0,0 +1,69 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2022 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getprevioustransition +description: > + RangeError thrown if an invalid ISO string (or syntactically valid ISO string + that is not supported) is used as an Instant +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + // invalid ISO strings: + "", + "invalid iso8601", + "2020-01-00T00:00Z", + "2020-01-32T00:00Z", + "2020-02-30T00:00Z", + "2021-02-29T00:00Z", + "2020-00-01T00:00Z", + "2020-13-01T00:00Z", + "2020-01-01TZ", + "2020-01-01T25:00:00Z", + "2020-01-01T01:60:00Z", + "2020-01-01T01:60:61Z", + "2020-01-01T00:00Zjunk", + "2020-01-01T00:00:00Zjunk", + "2020-01-01T00:00:00.000000000Zjunk", + "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-01T00:00Z", + "2020-001-01T00:00Z", + "2020-01-001T00:00Z", + "2020-01-01T001Z", + "2020-01-01T01:001Z", + "2020-01-01T01:01:001Z", + // valid, but forms not supported in Temporal: + "2020-W01-1T00:00Z", + "2020-001T00:00Z", + "+0002020-01-01T00:00Z", + // may be valid in other contexts, but insufficient information for Instant: + "2020-01", + "+002020-01", + "01-01", + "2020-W01", + "P1Y", + "-P12Y", + "2020-01-01", + "2020-01-01T00", + "2020-01-01T00:00", + "2020-01-01T00:00:00", + "2020-01-01T00:00:00.000000000", + // valid, but outside the supported range: + "-999999-01-01T00:00Z", + "+999999-01-01T00:00Z", +]; + +const instance = new Temporal.TimeZone("UTC"); +for (const arg of invalidStrings) { + assert.throws( + RangeError, + () => instance.getPreviousTransition(arg), + `"${arg}" should not be a valid ISO string for an Instant` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-calendar.js new file mode 100644 index 0000000000..9aef6ab2a8 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-calendar.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.timezone.prototype.getprevioustransition +description: > + More than one calendar annotation is not syntactical if any have the criical + flag +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[!u-ca=iso8601][u-ca=iso8601]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][!u-ca=iso8601]", + "1970-01-01T00:00Z[u-ca=iso8601][foo=bar][!u-ca=iso8601]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPreviousTransition(arg), + `reject more than one calendar annotation if any critical: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-time-zone.js new file mode 100644 index 0000000000..2903f9d7e2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: More than one time zone annotation is not syntactical +features: [Temporal] +---*/ + +const invalidStrings = [ + "1970-01-01T00:00Z[UTC][UTC]", + "1970-01-01T00:00Z[!UTC][UTC]", + "1970-01-01T00:00Z[UTC][!UTC]", + "1970-01-01T00:00Z[UTC][u-ca=iso8601][UTC]", + "1970-01-01T00:00Z[UTC][foo=bar][UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPreviousTransition(arg), + `reject more than one time zone annotation: ${arg}` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-time-separators.js new file mode 100644 index 0000000000..8e6d11d103 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Time separator in string argument can vary +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z", "uppercase T"], + ["1970-01-01t00:00Z", "lowercase T"], + ["1970-01-01 00:00Z", "space between date and time"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPreviousTransition(arg); + + assert.sameValue( + result, + null, + `variant time separators (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-time-zone-annotation.js new file mode 100644 index 0000000000..fe3c987a08 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Various forms of time zone annotation; critical flag has no effect +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[Asia/Kolkata]", "named, with Z"], + ["1970-01-01T00:00Z[!Europe/Vienna]", "named, with Z and !"], + ["1970-01-01T00:00Z[+00:00]", "numeric, with Z"], + ["1970-01-01T00:00Z[!-02:30]", "numeric, with Z and !"], + ["1970-01-01T00:00+00:00[UTC]", "named, with offset"], + ["1970-01-01T00:00+00:00[!Africa/Abidjan]", "named, with offset and !"], + ["1970-01-01T00:00+00:00[-08:00]", "numeric, with offset"], + ["1970-01-01T00:00+00:00[!+01:00]", "numeric, with offset and !"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPreviousTransition(arg); + + assert.sameValue( + result, + null, + `time zone annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js new file mode 100644 index 0000000000..d998b85a68 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Various forms of unknown annotation +features: [Temporal] +---*/ + +const tests = [ + ["1970-01-01T00:00Z[foo=bar]", "alone"], + ["1970-01-01T00:00Z[UTC][foo=bar]", "with time zone"], + ["1970-01-01T00:00Z[u-ca=iso8601][foo=bar]", "with calendar"], + ["1970-01-01T00:00Z[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"], + ["1970-01-01T00:00Z[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"], +]; + +const instance = new Temporal.TimeZone("UTC"); + +tests.forEach(([arg, description]) => { + const result = instance.getPreviousTransition(arg); + + assert.sameValue( + result, + null, + `unknown annotation (${description})` + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js new file mode 100644 index 0000000000..0519c26435 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-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.timezone.prototype.getprevioustransition +description: > + Appropriate error thrown when argument cannot be converted to a valid string + for Instant +features: [BigInt, Symbol, Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const primitiveTests = [ + [undefined, "undefined"], + [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"], + [{}, "plain object"], + [Temporal.Instant, "Temporal.Instant, object"], +]; + +for (const [arg, description] of primitiveTests) { + assert.throws( + typeof arg === "string" || (typeof arg === "object" && arg !== null) || typeof arg === "function" + ? RangeError + : TypeError, + () => instance.getPreviousTransition(arg), + `${description} does not convert to a valid ISO string` + ); +} + +const typeErrorTests = [ + [Symbol(), "symbol"], + [Temporal.Instant.prototype, "Temporal.Instant.prototype, object"], // fails brand check in toString() +]; + +for (const [arg, description] of typeErrorTests) { + assert.throws(TypeError, () => instance.getPreviousTransition(arg), `${description} does not convert to a string`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.js new file mode 100644 index 0000000000..dcc93e83c5 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.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.timezone.prototype.getprevioustransition +description: Fast path for converting Temporal.ZonedDateTime to Temporal.Instant +info: | + sec-temporal.timezone.prototype.getprevioustransition step 3: + 3. Set _startingPoint_ to ? ToTemporalInstant(_startingPoint_). + sec-temporal-totemporalinstant step 1.b: + b. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return ! CreateTemporalInstant(_item_.[[Nanoseconds]]). +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalInstantFastPath((datetime) => { + const timeZone = Temporal.TimeZone.from("UTC"); + const result = timeZone.getPreviousTransition(datetime); + assert.sameValue(result, null, "transition result"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/branding.js new file mode 100644 index 0000000000..5d8f674b80 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const getPreviousTransition = Temporal.TimeZone.prototype.getPreviousTransition; + +assert.sameValue(typeof getPreviousTransition, "function"); + +const args = [new Temporal.Instant(0n)]; + +assert.throws(TypeError, () => getPreviousTransition.apply(undefined, args), "undefined"); +assert.throws(TypeError, () => getPreviousTransition.apply(null, args), "null"); +assert.throws(TypeError, () => getPreviousTransition.apply(true, args), "true"); +assert.throws(TypeError, () => getPreviousTransition.apply("", args), "empty string"); +assert.throws(TypeError, () => getPreviousTransition.apply(Symbol(), args), "symbol"); +assert.throws(TypeError, () => getPreviousTransition.apply(1, args), "1"); +assert.throws(TypeError, () => getPreviousTransition.apply({}, args), "plain object"); +assert.throws(TypeError, () => getPreviousTransition.apply(Temporal.TimeZone, args), "Temporal.TimeZone"); +assert.throws(TypeError, () => getPreviousTransition.apply(Temporal.TimeZone.prototype, args), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/builtin.js new file mode 100644 index 0000000000..0051ee5e68 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: > + Tests that Temporal.TimeZone.prototype.getPreviousTransition + 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.TimeZone.prototype.getPreviousTransition), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.getPreviousTransition), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.getPreviousTransition), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.getPreviousTransition.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js new file mode 100644 index 0000000000..7bf8f08e9d --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.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.timezone.prototype.getprevioustransition +description: String arguments at the limit of the representable range +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const minInstantStrings = [ + "-271821-04-20T00:00Z", + "-271821-04-19T23:00-01:00", + "-271821-04-19T00:00:00.000000001-23:59:59.999999999", +]; +for (const str of minInstantStrings) { + assert.sameValue(instance.getPreviousTransition(str), null, `instant string ${str} should be valid`); +} + +const maxInstantStrings = [ + "+275760-09-13T00:00Z", + "+275760-09-13T01:00+01:00", + "+275760-09-13T23:59:59.999999999+23:59:59.999999999", +]; + +for (const str of maxInstantStrings) { + assert.sameValue(instance.getPreviousTransition(str), null, `instant string ${str} should be valid`); +} + +const outOfRangeInstantStrings = [ + "-271821-04-19T23:59:59.999999999Z", + "-271821-04-19T23:00-00:59:59.999999999", + "-271821-04-19T00:00:00-23:59:59.999999999", + "-271821-04-19T00:00:00-24:00", + "+275760-09-13T00:00:00.000000001Z", + "+275760-09-13T01:00+00:59:59.999999999", + "+275760-09-14T00:00+23:59:59.999999999", + "+275760-09-14T00:00+24:00", +]; + +for (const str of outOfRangeInstantStrings) { + assert.throws(RangeError, () => instance.getPreviousTransition(str), `instant string ${str} should not be valid`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string.js new file mode 100644 index 0000000000..1b29755e93 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.getprevioustransition +description: Conversion of ISO date-time strings to Temporal.Instant instances +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +let str = "1970-01-01T00:00"; +assert.throws(RangeError, () => instance.getPreviousTransition(str), "bare date-time string is not an instant"); +str = "1970-01-01T00:00[UTC]"; +assert.throws(RangeError, () => instance.getPreviousTransition(str), "date-time + IANA annotation is not an instant"); + +// The following are all valid strings so should not throw: + +const valids = [ + "1970-01-01T00:00Z", + "1970-01-01T00:00+01:00", + "1970-01-01T00:00Z[UTC]", + "1970-01-01T00:00+01:00[UTC]", + "1970-01-01T00:00Z[u-ca=hebrew]", + "1970-01-01T00:00+01:00[u-ca=hebrew]", + "1970-01-01T00:00+01:00[Etc/Ignored][u-ca=hebrew]", +]; +for (const str of valids) { + const result = instance.getPreviousTransition(str); + assert.sameValue(result, null); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/leap-second.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/leap-second.js new file mode 100644 index 0000000000..b2db8c3b61 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/leap-second.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.timezone.prototype.getprevioustransition +description: Leap second is a valid ISO string for Instant +features: [Temporal] +---*/ + +const instance = new Temporal.TimeZone("UTC"); + +const arg = "2016-12-31T23:59:60Z"; +const result = instance.getPreviousTransition(arg); +assert.sameValue( + result, + null, + "leap second is a valid ISO string for Instant" +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/length.js new file mode 100644 index 0000000000..ce577d9e1f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Temporal.TimeZone.prototype.getPreviousTransition.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.TimeZone.prototype.getPreviousTransition, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/name.js new file mode 100644 index 0000000000..863f68d954 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Temporal.TimeZone.prototype.getPreviousTransition.name is "getPreviousTransition". +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.TimeZone.prototype.getPreviousTransition, "name", { + value: "getPreviousTransition", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/not-a-constructor.js new file mode 100644 index 0000000000..ff62b8aeeb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: > + Temporal.TimeZone.prototype.getPreviousTransition 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.TimeZone.prototype.getPreviousTransition(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.getPreviousTransition), false, + "isConstructor(Temporal.TimeZone.prototype.getPreviousTransition)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/prop-desc.js new file mode 100644 index 0000000000..06f2b98876 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: The "getPreviousTransition" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.getPreviousTransition, + "function", + "`typeof TimeZone.prototype.getPreviousTransition` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "getPreviousTransition", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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/TimeZone/prototype/getPreviousTransition/year-zero.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/year-zero.js new file mode 100644 index 0000000000..1d0208c42f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/getPreviousTransition/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.timezone.prototype.getprevioustransition +description: Negative zero, as an extended year, is rejected +features: [Temporal, arrow-function] +---*/ + +const invalidStrings = [ + "-000000-03-30T00:45Z", + "-000000-03-30T01:45+01:00", + "-000000-03-30T01:45:00+00:00[UTC]", +]; +const instance = new Temporal.TimeZone("UTC"); +invalidStrings.forEach((arg) => { + assert.throws( + RangeError, + () => instance.getPreviousTransition(arg), + "reject minus zero as extended year" + ); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/branding.js new file mode 100644 index 0000000000..0673aa9475 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/branding.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-get-temporal.timezone.prototype.id +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.TimeZone.prototype, "id"); +const id = descriptor.get; + +assert.sameValue(typeof id, "function"); + +assert.throws(TypeError, () => id.call(undefined), "undefined"); +assert.throws(TypeError, () => id.call(null), "null"); +assert.throws(TypeError, () => id.call(true), "true"); +assert.throws(TypeError, () => id.call(""), "empty string"); +assert.throws(TypeError, () => id.call(Symbol()), "symbol"); +assert.throws(TypeError, () => id.call(1), "1"); +assert.throws(TypeError, () => id.call({}), "plain object"); +assert.throws(TypeError, () => id.call(Temporal.TimeZone), "Temporal.TimeZone"); +assert.throws(TypeError, () => id.call(Temporal.TimeZone.prototype), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js new file mode 100644 index 0000000000..31918f4866 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-get-temporal.timezone.prototype.id +description: Getter does not call toString(), returns the ID from internal slot +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = []; + +const timeZone = new Temporal.TimeZone("UTC"); +TemporalHelpers.observeProperty(actual, timeZone, Symbol.toPrimitive, undefined); +TemporalHelpers.observeProperty(actual, timeZone, "toString", function () { + actual.push("call timeZone.toString"); + return "time zone"; +}); + +const result = timeZone.id; +assert.compareArray(actual, expected); +assert.sameValue(result, "UTC"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/prop-desc.js new file mode 100644 index 0000000000..f1e4358ba0 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/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.timezone.prototype.id +description: The "id" property of Temporal.TimeZone.prototype +features: [Temporal] +---*/ + +const descriptor = Object.getOwnPropertyDescriptor(Temporal.TimeZone.prototype, "id"); +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/TimeZone/prototype/id/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/id/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/prop-desc.js new file mode 100644 index 0000000000..040655cc05 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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-timezone-prototype +description: The "prototype" property of Temporal.TimeZone +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue(typeof Temporal.TimeZone.prototype, "object"); +assert.notSameValue(Temporal.TimeZone.prototype, null); + +verifyProperty(Temporal.TimeZone, "prototype", { + writable: false, + enumerable: false, + configurable: false, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/shell.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/branding.js new file mode 100644 index 0000000000..c2c2d70b43 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toJSON = Temporal.TimeZone.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.TimeZone), "Temporal.TimeZone"); +assert.throws(TypeError, () => toJSON.call(Temporal.TimeZone.prototype), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/builtin.js new file mode 100644 index 0000000000..6be9473aca --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: > + Tests that Temporal.TimeZone.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.TimeZone.prototype.toJSON), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.toJSON), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.toJSON), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.toJSON.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/length.js new file mode 100644 index 0000000000..c9643b2cb4 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: Temporal.TimeZone.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.TimeZone.prototype.toJSON, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/name.js new file mode 100644 index 0000000000..120b740fcb --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: Temporal.TimeZone.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.TimeZone.prototype.toJSON, "name", { + value: "toJSON", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/not-a-constructor.js new file mode 100644 index 0000000000..1e2dd72b4b --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: > + Temporal.TimeZone.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.TimeZone.prototype.toJSON(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.toJSON), false, + "isConstructor(Temporal.TimeZone.prototype.toJSON)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/prop-desc.js new file mode 100644 index 0000000000..4d6365274f --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tojson +description: The "toJSON" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.toJSON, + "function", + "`typeof TimeZone.prototype.toJSON` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "toJSON", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/returns-identifier-slot.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/returns-identifier-slot.js new file mode 100644 index 0000000000..9681aab599 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/returns-identifier-slot.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.timezone.prototype.tojson +description: toJSON() returns the internal slot value +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const actual = []; + +const timeZone = new Temporal.TimeZone("UTC"); +TemporalHelpers.observeProperty(actual, timeZone, Symbol.toPrimitive, undefined); +TemporalHelpers.observeProperty(actual, timeZone, "id", "Etc/Bogus"); +TemporalHelpers.observeProperty(actual, timeZone, "toString", function () { + actual.push("call timeZone.toString"); + return "Etc/TAI"; +}); + +const result = timeZone.toJSON(); +assert.sameValue(result, "UTC", "toJSON gets the internal slot value"); +assert.compareArray(actual, [], "should not invoke any observable operations"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toJSON/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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/TimeZone/prototype/toString/branding.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/branding.js new file mode 100644 index 0000000000..ec12ff4fbd --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: Throw a TypeError if the receiver is invalid +features: [Symbol, Temporal] +---*/ + +const toString = Temporal.TimeZone.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.TimeZone), "Temporal.TimeZone"); +assert.throws(TypeError, () => toString.call(Temporal.TimeZone.prototype), "Temporal.TimeZone.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/builtin.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/builtin.js new file mode 100644 index 0000000000..d1626775aa --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: > + Tests that Temporal.TimeZone.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.TimeZone.prototype.toString), + true, "Built-in objects must be extensible."); + +assert.sameValue(Object.prototype.toString.call(Temporal.TimeZone.prototype.toString), + "[object Function]", "Object.prototype.toString"); + +assert.sameValue(Object.getPrototypeOf(Temporal.TimeZone.prototype.toString), + Function.prototype, "prototype"); + +assert.sameValue(Temporal.TimeZone.prototype.toString.hasOwnProperty("prototype"), + false, "prototype property"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/length.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/length.js new file mode 100644 index 0000000000..793d2c25f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: Temporal.TimeZone.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.TimeZone.prototype.toString, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/name.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/name.js new file mode 100644 index 0000000000..1197a8faa9 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: Temporal.TimeZone.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.TimeZone.prototype.toString, "name", { + value: "toString", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/not-a-constructor.js new file mode 100644 index 0000000000..ce6e8d490a --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: > + Temporal.TimeZone.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.TimeZone.prototype.toString(); +}, "Calling as constructor"); + +assert.sameValue(isConstructor(Temporal.TimeZone.prototype.toString), false, + "isConstructor(Temporal.TimeZone.prototype.toString)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/prop-desc.js new file mode 100644 index 0000000000..f4b0067d12 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype.tostring +description: The "toString" property of Temporal.TimeZone.prototype +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue( + typeof Temporal.TimeZone.prototype.toString, + "function", + "`typeof TimeZone.prototype.toString` is `function`" +); + +verifyProperty(Temporal.TimeZone.prototype, "toString", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toString/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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/TimeZone/prototype/toStringTag/browser.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/browser.js diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js new file mode 100644 index 0000000000..fae1256a56 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/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.timezone.prototype-@@tostringtag +description: The @@toStringTag property of Temporal.TimeZone +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.TimeZone.prototype, Symbol.toStringTag, { + value: "Temporal.TimeZone", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/shell.js b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/Temporal/TimeZone/prototype/toStringTag/shell.js |