diff --git a/harness/temporalHelpers.js b/harness/temporalHelpers.js new file mode 100644 index 0000000000..984902aa7b --- /dev/null +++ b/harness/temporalHelpers.js @@ -0,0 +1,82 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + This defines helper objects and functions for testing Temporal. +defines: [TemporalHelpers] +features: [Symbol.species, Symbol.iterator, Temporal] +---*/ + +var TemporalHelpers = { + /* + * Check that any calendar-carrying Temporal object has its [[Calendar]] + * internal slot read by ToTemporalCalendar, and does not fetch the calendar + * by calling getters. + * The custom calendar object is passed in to func() so that it can do its + * own additional assertions involving the calendar if necessary. (Sometimes + * there is nothing to assert as the calendar isn't stored anywhere that can + * be asserted about.) + */ + checkToTemporalCalendarFastPath(func) { + class CalendarFastPathCheck extends Temporal.Calendar { + constructor() { + super("iso8601"); + } + + toString() { + return "fast-path-check"; + } + } + const calendar = new CalendarFastPathCheck(); + + const plainDate = new Temporal.PlainDate(2000, 5, 2, calendar); + const plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); + const plainMonthDay = new Temporal.PlainMonthDay(5, 2, calendar); + const plainYearMonth = new Temporal.PlainYearMonth(2000, 5, calendar); + const zonedDateTime = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar); + + [plainDate, plainDateTime, plainMonthDay, plainYearMonth, zonedDateTime].forEach((temporalObject) => { + const actual = []; + const expected = []; + + Object.defineProperty(temporalObject, "calendar", { + get() { + actual.push("get calendar"); + return calendar; + }, + }); + + func(temporalObject, calendar); + assert.compareArray(actual, expected, "calendar getter not called"); + }); + }, + + /* + * specificOffsetTimeZone(): + * + * This returns an instance of a custom time zone class, which returns a + * specific custom value from its getOffsetNanosecondsFrom() method. This is + * for the purpose of testing the validation of what this method returns. + * + * It also returns an empty array from getPossibleInstantsFor(), so as to + * trigger calls to getOffsetNanosecondsFor() when used from the + * BuiltinTimeZoneGetInstantFor operation. + */ + specificOffsetTimeZone(offsetValue) { + class SpecificOffsetTimeZone extends Temporal.TimeZone { + constructor(offsetValue) { + super("UTC"); + this._offsetValue = offsetValue; + } + + getOffsetNanosecondsFor() { + return this._offsetValue; + } + + getPossibleInstantsFor() { + return []; + } + } + return new SpecificOffsetTimeZone(offsetValue); + }, +}; diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-function.js b/test/built-ins/Temporal/now/plainDateTime/calendar-function.js new file mode 100644 index 0000000000..e780917e8c --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-function.js @@ -0,0 +1,46 @@ +// 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.now.plaindatetime +description: Behavior when provided calendar value is a function +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + "has timeZone.timeZone", + "get timeZone.getOffsetNanosecondsFor", + "call timeZone.getOffsetNanosecondsFor", +]; +const calendar = function() {}; +const timeZone = new Proxy({ + getOffsetNanosecondsFor(instant) { + actual.push("call timeZone.getOffsetNanosecondsFor"); + return -Number(instant.epochNanoseconds % 86400_000_000_000n); + }, +}, { + has(target, property) { + actual.push(`has timeZone.${property}`); + return property in target; + }, + get(target, property) { + actual.push(`get timeZone.${property}`); + return target[property]; + }, +}); + +Object.defineProperty(Temporal.Calendar, "from", { + get() { + actual.push("get Temporal.Calendar.from"); + return undefined; + }, +}); + +const result = Temporal.now.plainDateTime(calendar, timeZone); +for (const property of ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]) { + assert.sameValue(result[property], 0, property); +} + +assert.compareArray(actual, expected); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-call-tostring.js b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-call-tostring.js new file mode 100644 index 0000000000..52efb50883 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-call-tostring.js @@ -0,0 +1,20 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by invoking "toString" property +features: [Temporal] +---*/ + +var calendar = { + calendar: { + calendar: true, + toString: function() { + throw new Test262Error(); + }, + } +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime(calendar); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-get-calendar.js b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-get-calendar.js new file mode 100644 index 0000000000..d9161a6a8e --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-get-calendar.js @@ -0,0 +1,17 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by retrieving value of "calendar" property +features: [Temporal] +---*/ + +var calendar = { + get calendar() { + throw new Test262Error(); + }, +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime(calendar); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-calendar.js b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-calendar.js new file mode 100644 index 0000000000..c07d2308d1 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-calendar.js @@ -0,0 +1,20 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by checking presence of "calendar" property +features: [Temporal] +---*/ + +var calendar = new Proxy({}, { + has: function(target, property) { + if (property === 'calendar') { + throw new Test262Error(); + } + }, +}); + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime(calendar); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-nested-calendar.js b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-nested-calendar.js new file mode 100644 index 0000000000..f0d4c84858 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-object-fail-has-nested-calendar.js @@ -0,0 +1,21 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by checking presence of nested "calendar" property +features: [Temporal] +---*/ + +var calendar = { + calendar: new Proxy({}, { + has: function(target, property) { + if (property === 'calendar') { + throw new Test262Error(); + } + }, + }) +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime(calendar); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-object.js b/test/built-ins/Temporal/now/plainDateTime/calendar-object.js new file mode 100644 index 0000000000..74a7dec849 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-object.js @@ -0,0 +1,61 @@ +// 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.now.plaindatetime +description: Observable interactions with the provided calendar-like object +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + 'has calendar.calendar', + 'get calendar.calendar', + 'has nestedCalendar.calendar', + 'get nestedCalendar.Symbol(Symbol.toPrimitive)', + 'get nestedCalendar.toString', + 'call nestedCalendar.toString' +]; +const nestedCalendar = new Proxy({ + toString: function() { + actual.push('call nestedCalendar.toString'); + return 'iso8601'; + } +}, { + has(target, property) { + actual.push(`has nestedCalendar.${String(property)}`); + return property in target; + }, + get(target, property) { + actual.push(`get nestedCalendar.${String(property)}`); + return target[property]; + }, +}); +const calendar = new Proxy({ + calendar: nestedCalendar, + toString: function() { + actual.push('call calendar.toString'); + return 'iso8601'; + }, +}, { + has(target, property) { + actual.push(`has calendar.${String(property)}`); + return property in target; + }, + get(target, property) { + actual.push(`get calendar.${String(property)}`); + return target[property]; + }, +}); + +Object.defineProperty(Temporal.Calendar, 'from', { + get() { + actual.push('get Temporal.Calendar.from'); + return undefined; + }, +}); + +Temporal.now.plainDateTime(calendar); + +assert.compareArray(actual, expected); diff --git a/test/built-ins/Temporal/now/plainDateTime/calendar-temporal-object.js b/test/built-ins/Temporal/now/plainDateTime/calendar-temporal-object.js new file mode 100644 index 0000000000..e3260accf8 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/calendar-temporal-object.js @@ -0,0 +1,22 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots +info: | + sec-temporal.now.plaindatetime step 1: + 1. Return ? SystemDateTime(_temporalTimeZoneLike_, _calendar_). + sec-temporal-systemdatetime step 3: + 3. Let _calendar_ be ? ToTemporalCalendar(_calendarLike_). + sec-temporal-totemporalcalendar step 1.a: + a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + i. Return _temporalCalendarLike_.[[Calendar]]. +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject, calendar) => { + const result = Temporal.now.plainDateTime(temporalObject); + assert.sameValue(result.calendar, calendar, "Temporal object coerced to calendar"); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/extensible.js b/test/built-ins/Temporal/now/plainDateTime/extensible.js new file mode 100644 index 0000000000..85c91d80b0 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/extensible.js @@ -0,0 +1,9 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Temporal.now.plainDateTime is extensible. +features: [Temporal] +---*/ + +assert(Object.isExtensible(Temporal.now.plainDateTime)); diff --git a/test/built-ins/Temporal/now/plainDateTime/length.js b/test/built-ins/Temporal/now/plainDateTime/length.js new file mode 100644 index 0000000000..135faddbd3 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/length.js @@ -0,0 +1,25 @@ +// 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.now.plaindatetime +description: The `length` property of Temporal.now.plainDateTime +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.now.plainDateTime, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/name.js b/test/built-ins/Temporal/now/plainDateTime/name.js new file mode 100644 index 0000000000..6b7818aa4f --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/name.js @@ -0,0 +1,16 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plainDateTime +description: Temporal.now.plainDateTime.name is "plainDateTime". +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +assert.sameValue(Temporal.now.plainDateTime.name, 'plainDateTime'); + +verifyProperty(Temporal.now.plainDateTime, 'name', { + enumerable: false, + writable: false, + configurable: true +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/not-a-constructor.js b/test/built-ins/Temporal/now/plainDateTime/not-a-constructor.js new file mode 100644 index 0000000000..4f8f19ac4d --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/not-a-constructor.js @@ -0,0 +1,14 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Temporal.now.plainDateTime does not implement [[Construct]] +includes: [isConstructor.js] +features: [Reflect.construct, Temporal] +---*/ + +assert.sameValue(isConstructor(Temporal.now.plainDateTime), false, 'isConstructor(Temporal.now.plainDateTime) must return false'); + +assert.throws(TypeError, () => { + new Temporal.now.plainDateTime(); +}, '`new Temporal.now.plainDateTime()` throws TypeError'); diff --git a/test/built-ins/Temporal/now/plainDateTime/prop-desc.js b/test/built-ins/Temporal/now/plainDateTime/prop-desc.js new file mode 100644 index 0000000000..d2dfb0d282 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/prop-desc.js @@ -0,0 +1,14 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: The "plainDateTime" property of Temporal.now +includes: [propertyHelper.js] +features: [Temporal] +---*/ + +verifyProperty(Temporal.now, 'plainDateTime', { + enumerable: false, + writable: true, + configurable: true +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/return-value.js b/test/built-ins/Temporal/now/plainDateTime/return-value.js new file mode 100644 index 0000000000..e0258586ce --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/return-value.js @@ -0,0 +1,20 @@ +// 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.now.plaindatetime +description: Return value describes the start of a day +features: [Temporal] +---*/ + +const calendar = Temporal.Calendar.from("iso8601"); +const timeZone = { + getOffsetNanosecondsFor(instant) { + return -Number(instant.epochNanoseconds % 86400_000_000_000n); + } +}; + +const result = Temporal.now.plainDateTime(calendar, timeZone); +for (const property of ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]) { + assert.sameValue(result[property], 0, property); +} diff --git a/test/built-ins/Temporal/now/plainDateTime/time-zone-undefined.js b/test/built-ins/Temporal/now/plainDateTime/time-zone-undefined.js new file mode 100644 index 0000000000..43d6a286c1 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/time-zone-undefined.js @@ -0,0 +1,29 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +description: Functions when time zone argument is omitted +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = []; + +Object.defineProperty(Temporal.TimeZone, "from", { + get() { + actual.push("get Temporal.TimeZone.from"); + return undefined; + }, +}); + +const resultExplicit = Temporal.now.plainDateTime("iso8601", undefined); +assert(resultExplicit instanceof Temporal.PlainDateTime); + +assert.compareArray(actual, expected, "Temporal.TimeZone.from should not be called"); + +const resultImplicit = Temporal.now.plainDateTime("iso8601"); +assert(resultImplicit instanceof Temporal.PlainDateTime); + +assert.compareArray(actual, expected, "Temporal.TimeZone.from should not be called"); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-invocation.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-invocation.js new file mode 100644 index 0000000000..0fe33230d8 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-invocation.js @@ -0,0 +1,25 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Correctly invokes `getOffsetNanosecondsFor` method of TimeZone-like objects +features: [Temporal] +---*/ + +var calls = []; +var timeZone = { + getOffsetNanosecondsFor: function() { + calls.push({ + args: arguments, + this: this + }); + return 0; + }, +}; + +Temporal.now.plainDateTime('iso8601', timeZone); + +assert.sameValue(calls.length, 1, 'call count'); +assert.sameValue(calls[0].args.length, 1, 'arguments'); +assert(calls[0].args[0] instanceof Temporal.Instant); +assert.sameValue(calls[0].this, timeZone); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-integer.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-integer.js new file mode 100644 index 0000000000..b18f8c2228 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-integer.js @@ -0,0 +1,15 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[3600_000_000_000.5, NaN].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + + assert.throws(RangeError, () => Temporal.now.plainDateTime("iso8601", timeZone)); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-method.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-method.js new file mode 100644 index 0000000000..f35f30bdd1 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-non-method.js @@ -0,0 +1,15 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Rejects when `getOffsetNanosecondsFor` property is not a method +features: [Temporal] +---*/ + +var timeZone = { + getOffsetNanosecondsFor: 7 +}; + +assert.throws(TypeError, function() { + Temporal.now.plainDateTime('iso8601', timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-not-a-number.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-not-a-number.js new file mode 100644 index 0000000000..d080e76ab4 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-not-a-number.js @@ -0,0 +1,33 @@ +// 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.now.plaindatetime +description: Rejects non-numeric nanosecond values reported by TimeZone-like object +features: [Temporal] +---*/ + +const invalidValues = [ + undefined, + null, + true, + "2020-01-01T12:45:36", + Symbol(), + 2n, + {}, + Temporal.PlainDateTime, + Temporal.PlainDateTime.prototype, +]; + +for (const dateTime of invalidValues) { + let callCount = 0; + const timeZone = { + getOffsetNanosecondsFor(instant, calendar) { + callCount += 1; + return dateTime; + }, + }; + + assert.throws(TypeError, () => Temporal.now.plainDateTime("iso8601", timeZone)); + assert.sameValue(callCount, 1, 'Invoked `getOffsetNanosecondsFor`'); +} diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js new file mode 100644 index 0000000000..ba14c11cff --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-out-of-range.js @@ -0,0 +1,15 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +description: RangeError thrown if time zone reports an offset that is out of range +features: [Temporal] +includes: [temporalHelpers.js] +---*/ + +[-86400_000_000_001, 86400_000_000_001, -Infinity, Infinity].forEach((wrongOffset) => { + const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset); + + assert.throws(RangeError, () => Temporal.now.plainDateTime("iso8601", timeZone)); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-poisoned.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-poisoned.js new file mode 100644 index 0000000000..b0780d260a --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-poisoned.js @@ -0,0 +1,17 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error when accessing `getOffsetNanosecondsFor` property throws +features: [Temporal] +---*/ + +var timeZone = { + get getOffsetNanosecondsFor() { + throw new Test262Error(); + } +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime('iso8601', timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-throws.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-throws.js new file mode 100644 index 0000000000..8bef0b8482 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-throws.js @@ -0,0 +1,17 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error when `getOffsetNanosecondsFor` throws +features: [Temporal] +---*/ + +var timeZone = { + getOffsetNanosecondsFor() { + throw new Test262Error(); + } +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime('iso8601', timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js new file mode 100644 index 0000000000..89b06145f9 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-getoffsetnanosecondsfor-wrong-type.js @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.now.plaindatetime +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); + + assert.throws(TypeError, () => Temporal.now.plainDateTime("iso8601", timeZone)); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-call-tostring.js b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-call-tostring.js new file mode 100644 index 0000000000..6d6c18111f --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-call-tostring.js @@ -0,0 +1,20 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by invoking "toString" property +features: [Temporal] +---*/ + +var timeZone = { + timeZone: { + timeZone: true, + toString: function() { + throw new Test262Error(); + }, + } +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime("iso8601", timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-get-timezone.js b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-get-timezone.js new file mode 100644 index 0000000000..98a0d91423 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-get-timezone.js @@ -0,0 +1,17 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by retrieving value of "timeZone" property +features: [Temporal] +---*/ + +var timeZone = { + get timeZone() { + throw new Test262Error(); + }, +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime("iso8601", timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-nested-timezone.js b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-nested-timezone.js new file mode 100644 index 0000000000..61d3540d6a --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-nested-timezone.js @@ -0,0 +1,21 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by checking presence of nested "timeZone" property +features: [Temporal] +---*/ + +var timeZone = { + timeZone: new Proxy({}, { + has: function(target, property) { + if (property === 'timeZone') { + throw new Test262Error(); + } + }, + }) +}; + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime("iso8601", timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-timezone.js b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-timezone.js new file mode 100644 index 0000000000..da56d1ed21 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-object-fail-has-timezone.js @@ -0,0 +1,19 @@ +// Copyright (C) 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-temporal.now.plaindatetime +description: Forwards error thrown by checking presence of "timeZone" property +features: [Temporal] +---*/ + +var timeZone = new Proxy({}, { + has: function(target, property) { + if (property === 'timeZone') { + throw new Test262Error(); + } + }, +}); + +assert.throws(Test262Error, function() { + Temporal.now.plainDateTime("iso8601", timeZone); +}); diff --git a/test/built-ins/Temporal/now/plainDateTime/timezone-object.js b/test/built-ins/Temporal/now/plainDateTime/timezone-object.js new file mode 100644 index 0000000000..381f47b634 --- /dev/null +++ b/test/built-ins/Temporal/now/plainDateTime/timezone-object.js @@ -0,0 +1,62 @@ +// 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.now.plaindatetime +description: Observable interactions with the provided timezone-like object +includes: [compareArray.js] +features: [Temporal] +---*/ + +const actual = []; +const expected = [ + "has timeZone.timeZone", + "get timeZone.timeZone", + "has nestedTimeZone.timeZone", + "get nestedTimeZone.getOffsetNanosecondsFor", + "call nestedTimeZone.getOffsetNanosecondsFor", +]; +const nestedTimeZone = new Proxy({ + getOffsetNanosecondsFor(instant) { + actual.push("call nestedTimeZone.getOffsetNanosecondsFor"); + assert.sameValue(instant instanceof Temporal.Instant, true, "Instant"); + return -Number(instant.epochNanoseconds % 86400_000_000_000n); + }, +}, { + has(target, property) { + actual.push(`has nestedTimeZone.${String(property)}`); + return property in target; + }, + get(target, property) { + actual.push(`get nestedTimeZone.${String(property)}`); + return target[property]; + }, +}); +const timeZone = new Proxy({ + timeZone: nestedTimeZone, + getOffsetNanosecondsFor(instant) { + actual.push("call timeZone.getOffsetNanosecondsFor"); + assert.sameValue(instant instanceof Temporal.Instant, true, "Instant"); + return -Number(instant.epochNanoseconds % 86400_000_000_000n); + }, +}, { + has(target, property) { + actual.push(`has timeZone.${property}`); + return property in target; + }, + get(target, property) { + actual.push(`get timeZone.${property}`); + return target[property]; + }, +}); + +Object.defineProperty(Temporal.TimeZone, "from", { + get() { + actual.push("get Temporal.TimeZone.from"); + return undefined; + }, +}); + +Temporal.now.plainDateTime("iso8601", timeZone); + +assert.compareArray(actual, expected);