Bug 1870246 - Part 1: Update test262. r=spidermonkey-reviewers,mgaudet
[gecko.git] / js / src / tests / test262 / intl402 / Temporal / PlainDateTime / compare / shell.js
blob30ddc7c2dd3ef6bf0ccd8379198750702428e7bb
1 // GENERATED, DO NOT EDIT
2 // file: temporalHelpers.js
3 // Copyright (C) 2021 Igalia, S.L. All rights reserved.
4 // This code is governed by the BSD license found in the LICENSE file.
5 /*---
6 description: |
7     This defines helper objects and functions for testing Temporal.
8 defines: [TemporalHelpers]
9 features: [Symbol.species, Symbol.iterator, Temporal]
10 ---*/
12 const ASCII_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/u;
14 function formatPropertyName(propertyKey, objectName = "") {
15   switch (typeof propertyKey) {
16     case "symbol":
17       if (Symbol.keyFor(propertyKey) !== undefined) {
18         return `${objectName}[Symbol.for('${Symbol.keyFor(propertyKey)}')]`;
19       } else if (propertyKey.description.startsWith('Symbol.')) {
20         return `${objectName}[${propertyKey.description}]`;
21       } else {
22         return `${objectName}[Symbol('${propertyKey.description}')]`
23       }
24     case "string":
25       if (propertyKey !== String(Number(propertyKey))) {
26         if (ASCII_IDENTIFIER.test(propertyKey)) {
27           return objectName ? `${objectName}.${propertyKey}` : propertyKey;
28         }
29         return `${objectName}['${propertyKey.replace(/'/g, "\\'")}']`
30       }
31       // fall through
32     default:
33       // integer or string integer-index
34       return `${objectName}[${propertyKey}]`;
35   }
38 const SKIP_SYMBOL = Symbol("Skip");
40 var TemporalHelpers = {
41   /*
42    * Codes and maximum lengths of months in the ISO 8601 calendar.
43    */
44   ISOMonths: [
45     { month: 1, monthCode: "M01", daysInMonth: 31 },
46     { month: 2, monthCode: "M02", daysInMonth: 29 },
47     { month: 3, monthCode: "M03", daysInMonth: 31 },
48     { month: 4, monthCode: "M04", daysInMonth: 30 },
49     { month: 5, monthCode: "M05", daysInMonth: 31 },
50     { month: 6, monthCode: "M06", daysInMonth: 30 },
51     { month: 7, monthCode: "M07", daysInMonth: 31 },
52     { month: 8, monthCode: "M08", daysInMonth: 31 },
53     { month: 9, monthCode: "M09", daysInMonth: 30 },
54     { month: 10, monthCode: "M10", daysInMonth: 31 },
55     { month: 11, monthCode: "M11", daysInMonth: 30 },
56     { month: 12, monthCode: "M12", daysInMonth: 31 }
57   ],
59   /*
60    * assertDuration(duration, years, ...,  nanoseconds[, description]):
61    *
62    * Shorthand for asserting that each field of a Temporal.Duration is equal to
63    * an expected value.
64    */
65   assertDuration(duration, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, description = "") {
66     assert(duration instanceof Temporal.Duration, `${description} instanceof`);
67     assert.sameValue(duration.years, years, `${description} years result`);
68     assert.sameValue(duration.months, months, `${description} months result`);
69     assert.sameValue(duration.weeks, weeks, `${description} weeks result`);
70     assert.sameValue(duration.days, days, `${description} days result`);
71     assert.sameValue(duration.hours, hours, `${description} hours result`);
72     assert.sameValue(duration.minutes, minutes, `${description} minutes result`);
73     assert.sameValue(duration.seconds, seconds, `${description} seconds result`);
74     assert.sameValue(duration.milliseconds, milliseconds, `${description} milliseconds result`);
75     assert.sameValue(duration.microseconds, microseconds, `${description} microseconds result`);
76     assert.sameValue(duration.nanoseconds, nanoseconds, `${description} nanoseconds result`);
77   },
79   /*
80    * assertDateDuration(duration, years, months, weeks, days, [, description]):
81    *
82    * Shorthand for asserting that each date field of a Temporal.Duration is
83    * equal to an expected value.
84    */
85   assertDateDuration(duration, years, months, weeks, days, description = "") {
86     assert(duration instanceof Temporal.Duration, `${description} instanceof`);
87     assert.sameValue(duration.years, years, `${description} years result`);
88     assert.sameValue(duration.months, months, `${description} months result`);
89     assert.sameValue(duration.weeks, weeks, `${description} weeks result`);
90     assert.sameValue(duration.days, days, `${description} days result`);
91     assert.sameValue(duration.hours, 0, `${description} hours result should be zero`);
92     assert.sameValue(duration.minutes, 0, `${description} minutes result should be zero`);
93     assert.sameValue(duration.seconds, 0, `${description} seconds result should be zero`);
94     assert.sameValue(duration.milliseconds, 0, `${description} milliseconds result should be zero`);
95     assert.sameValue(duration.microseconds, 0, `${description} microseconds result should be zero`);
96     assert.sameValue(duration.nanoseconds, 0, `${description} nanoseconds result should be zero`);
97   },
99   /*
100    * assertDurationsEqual(actual, expected[, description]):
101    *
102    * Shorthand for asserting that each field of a Temporal.Duration is equal to
103    * the corresponding field in another Temporal.Duration.
104    */
105   assertDurationsEqual(actual, expected, description = "") {
106     assert(expected instanceof Temporal.Duration, `${description} expected value should be a Temporal.Duration`);
107     TemporalHelpers.assertDuration(actual, expected.years, expected.months, expected.weeks, expected.days, expected.hours, expected.minutes, expected.seconds, expected.milliseconds, expected.microseconds, expected.nanoseconds, description);
108   },
110   /*
111    * assertInstantsEqual(actual, expected[, description]):
112    *
113    * Shorthand for asserting that two Temporal.Instants are of the correct type
114    * and equal according to their equals() methods.
115    */
116   assertInstantsEqual(actual, expected, description = "") {
117     assert(expected instanceof Temporal.Instant, `${description} expected value should be a Temporal.Instant`);
118     assert(actual instanceof Temporal.Instant, `${description} instanceof`);
119     assert(actual.equals(expected), `${description} equals method`);
120   },
122   /*
123    * assertPlainDate(date, year, ..., nanosecond[, description[, era, eraYear]]):
124    *
125    * Shorthand for asserting that each field of a Temporal.PlainDate is equal to
126    * an expected value. (Except the `calendar` property, since callers may want
127    * to assert either object equality with an object they put in there, or the
128    * value of date.calendarId.)
129    */
130   assertPlainDate(date, year, month, monthCode, day, description = "", era = undefined, eraYear = undefined) {
131     assert(date instanceof Temporal.PlainDate, `${description} instanceof`);
132     assert.sameValue(date.era, era, `${description} era result`);
133     assert.sameValue(date.eraYear, eraYear, `${description} eraYear result`);
134     assert.sameValue(date.year, year, `${description} year result`);
135     assert.sameValue(date.month, month, `${description} month result`);
136     assert.sameValue(date.monthCode, monthCode, `${description} monthCode result`);
137     assert.sameValue(date.day, day, `${description} day result`);
138   },
140   /*
141    * assertPlainDateTime(datetime, year, ..., nanosecond[, description[, era, eraYear]]):
142    *
143    * Shorthand for asserting that each field of a Temporal.PlainDateTime is
144    * equal to an expected value. (Except the `calendar` property, since callers
145    * may want to assert either object equality with an object they put in there,
146    * or the value of datetime.calendarId.)
147    */
148   assertPlainDateTime(datetime, year, month, monthCode, day, hour, minute, second, millisecond, microsecond, nanosecond, description = "", era = undefined, eraYear = undefined) {
149     assert(datetime instanceof Temporal.PlainDateTime, `${description} instanceof`);
150     assert.sameValue(datetime.era, era, `${description} era result`);
151     assert.sameValue(datetime.eraYear, eraYear, `${description} eraYear result`);
152     assert.sameValue(datetime.year, year, `${description} year result`);
153     assert.sameValue(datetime.month, month, `${description} month result`);
154     assert.sameValue(datetime.monthCode, monthCode, `${description} monthCode result`);
155     assert.sameValue(datetime.day, day, `${description} day result`);
156     assert.sameValue(datetime.hour, hour, `${description} hour result`);
157     assert.sameValue(datetime.minute, minute, `${description} minute result`);
158     assert.sameValue(datetime.second, second, `${description} second result`);
159     assert.sameValue(datetime.millisecond, millisecond, `${description} millisecond result`);
160     assert.sameValue(datetime.microsecond, microsecond, `${description} microsecond result`);
161     assert.sameValue(datetime.nanosecond, nanosecond, `${description} nanosecond result`);
162   },
164   /*
165    * assertPlainDateTimesEqual(actual, expected[, description]):
166    *
167    * Shorthand for asserting that two Temporal.PlainDateTimes are of the correct
168    * type, equal according to their equals() methods, and additionally that
169    * their calendar internal slots are the same value.
170    */
171   assertPlainDateTimesEqual(actual, expected, description = "") {
172     assert(expected instanceof Temporal.PlainDateTime, `${description} expected value should be a Temporal.PlainDateTime`);
173     assert(actual instanceof Temporal.PlainDateTime, `${description} instanceof`);
174     assert(actual.equals(expected), `${description} equals method`);
175     assert.sameValue(
176       actual.getISOFields().calendar,
177       expected.getISOFields().calendar,
178       `${description} calendar same value`
179     );
180   },
182   /*
183    * assertPlainMonthDay(monthDay, monthCode, day[, description [, referenceISOYear]]):
184    *
185    * Shorthand for asserting that each field of a Temporal.PlainMonthDay is
186    * equal to an expected value. (Except the `calendar` property, since callers
187    * may want to assert either object equality with an object they put in there,
188    * or the value of monthDay.calendarId().)
189    */
190   assertPlainMonthDay(monthDay, monthCode, day, description = "", referenceISOYear = 1972) {
191     assert(monthDay instanceof Temporal.PlainMonthDay, `${description} instanceof`);
192     assert.sameValue(monthDay.monthCode, monthCode, `${description} monthCode result`);
193     assert.sameValue(monthDay.day, day, `${description} day result`);
194     assert.sameValue(monthDay.getISOFields().isoYear, referenceISOYear, `${description} referenceISOYear result`);
195   },
197   /*
198    * assertPlainTime(time, hour, ..., nanosecond[, description]):
199    *
200    * Shorthand for asserting that each field of a Temporal.PlainTime is equal to
201    * an expected value.
202    */
203   assertPlainTime(time, hour, minute, second, millisecond, microsecond, nanosecond, description = "") {
204     assert(time instanceof Temporal.PlainTime, `${description} instanceof`);
205     assert.sameValue(time.hour, hour, `${description} hour result`);
206     assert.sameValue(time.minute, minute, `${description} minute result`);
207     assert.sameValue(time.second, second, `${description} second result`);
208     assert.sameValue(time.millisecond, millisecond, `${description} millisecond result`);
209     assert.sameValue(time.microsecond, microsecond, `${description} microsecond result`);
210     assert.sameValue(time.nanosecond, nanosecond, `${description} nanosecond result`);
211   },
213   /*
214    * assertPlainTimesEqual(actual, expected[, description]):
215    *
216    * Shorthand for asserting that two Temporal.PlainTimes are of the correct
217    * type and equal according to their equals() methods.
218    */
219   assertPlainTimesEqual(actual, expected, description = "") {
220     assert(expected instanceof Temporal.PlainTime, `${description} expected value should be a Temporal.PlainTime`);
221     assert(actual instanceof Temporal.PlainTime, `${description} instanceof`);
222     assert(actual.equals(expected), `${description} equals method`);
223   },
225   /*
226    * assertPlainYearMonth(yearMonth, year, month, monthCode[, description[, era, eraYear, referenceISODay]]):
227    *
228    * Shorthand for asserting that each field of a Temporal.PlainYearMonth is
229    * equal to an expected value. (Except the `calendar` property, since callers
230    * may want to assert either object equality with an object they put in there,
231    * or the value of yearMonth.calendarId.)
232    */
233   assertPlainYearMonth(yearMonth, year, month, monthCode, description = "", era = undefined, eraYear = undefined, referenceISODay = 1) {
234     assert(yearMonth instanceof Temporal.PlainYearMonth, `${description} instanceof`);
235     assert.sameValue(yearMonth.era, era, `${description} era result`);
236     assert.sameValue(yearMonth.eraYear, eraYear, `${description} eraYear result`);
237     assert.sameValue(yearMonth.year, year, `${description} year result`);
238     assert.sameValue(yearMonth.month, month, `${description} month result`);
239     assert.sameValue(yearMonth.monthCode, monthCode, `${description} monthCode result`);
240     assert.sameValue(yearMonth.getISOFields().isoDay, referenceISODay, `${description} referenceISODay result`);
241   },
243   /*
244    * assertZonedDateTimesEqual(actual, expected[, description]):
245    *
246    * Shorthand for asserting that two Temporal.ZonedDateTimes are of the correct
247    * type, equal according to their equals() methods, and additionally that
248    * their time zones and calendar internal slots are the same value.
249    */
250   assertZonedDateTimesEqual(actual, expected, description = "") {
251     assert(expected instanceof Temporal.ZonedDateTime, `${description} expected value should be a Temporal.ZonedDateTime`);
252     assert(actual instanceof Temporal.ZonedDateTime, `${description} instanceof`);
253     assert(actual.equals(expected), `${description} equals method`);
254     assert.sameValue(actual.timeZone, expected.timeZone, `${description} time zone same value`);
255     assert.sameValue(
256       actual.getISOFields().calendar,
257       expected.getISOFields().calendar,
258       `${description} calendar same value`
259     );
260   },
262   /*
263    * assertUnreachable(description):
264    *
265    * Helper for asserting that code is not executed. This is useful for
266    * assertions that methods of user calendars and time zones are not called.
267    */
268   assertUnreachable(description) {
269     let message = "This code should not be executed";
270     if (description) {
271       message = `${message}: ${description}`;
272     }
273     throw new Test262Error(message);
274   },
276   /*
277    * checkCalendarDateUntilLargestUnitSingular(func, expectedLargestUnitCalls):
278    *
279    * When an options object with a largestUnit property is synthesized inside
280    * Temporal and passed to user code such as calendar.dateUntil(), the value of
281    * the largestUnit property should be in the singular form, even if the input
282    * was given in the plural form.
283    * (This doesn't apply when the options object is passed through verbatim.)
284    *
285    * func(calendar, largestUnit, index) is the operation under test. It's called
286    * with an instance of a calendar that keeps track of which largestUnit is
287    * passed to dateUntil(), each key of expectedLargestUnitCalls in turn, and
288    * the key's numerical index in case the function needs to generate test data
289    * based on the index. At the end, the actual values passed to dateUntil() are
290    * compared with the array values of expectedLargestUnitCalls.
291    */
292   checkCalendarDateUntilLargestUnitSingular(func, expectedLargestUnitCalls) {
293     const actual = [];
295     class DateUntilOptionsCalendar extends Temporal.Calendar {
296       constructor() {
297         super("iso8601");
298       }
300       dateUntil(earlier, later, options) {
301         actual.push(options.largestUnit);
302         return super.dateUntil(earlier, later, options);
303       }
305       toString() {
306         return "date-until-options";
307       }
308     }
310     const calendar = new DateUntilOptionsCalendar();
311     Object.entries(expectedLargestUnitCalls).forEach(([largestUnit, expected], index) => {
312       func(calendar, largestUnit, index);
313       assert.compareArray(actual, expected, `largestUnit passed to calendar.dateUntil() for largestUnit ${largestUnit}`);
314       actual.splice(0); // empty it for the next check
315     });
316   },
318   /*
319    * checkPlainDateTimeConversionFastPath(func):
320    *
321    * ToTemporalDate and ToTemporalTime should both, if given a
322    * Temporal.PlainDateTime instance, convert to the desired type by reading the
323    * PlainDateTime's internal slots, rather than calling any getters.
324    *
325    * func(datetime, calendar) is the actual operation to test, that must
326    * internally call the abstract operation ToTemporalDate or ToTemporalTime.
327    * It is passed a Temporal.PlainDateTime instance, as well as the instance's
328    * calendar object (so that it doesn't have to call the calendar getter itself
329    * if it wants to make any assertions about the calendar.)
330    */
331   checkPlainDateTimeConversionFastPath(func, message = "checkPlainDateTimeConversionFastPath") {
332     const actual = [];
333     const expected = [];
335     const calendar = new Temporal.Calendar("iso8601");
336     const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar);
337     const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.PlainDateTime.prototype);
338     ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].forEach((property) => {
339       Object.defineProperty(datetime, property, {
340         get() {
341           actual.push(`get ${formatPropertyName(property)}`);
342           const value = prototypeDescrs[property].get.call(this);
343           return {
344             toString() {
345               actual.push(`toString ${formatPropertyName(property)}`);
346               return value.toString();
347             },
348             valueOf() {
349               actual.push(`valueOf ${formatPropertyName(property)}`);
350               return value;
351             },
352           };
353         },
354       });
355     });
356     Object.defineProperty(datetime, "calendar", {
357       get() {
358         actual.push("get calendar");
359         return calendar;
360       },
361     });
363     func(datetime, calendar);
364     assert.compareArray(actual, expected, `${message}: property getters not called`);
365   },
367   /*
368    * Check that an options bag that accepts units written in the singular form,
369    * also accepts the same units written in the plural form.
370    * func(unit) should call the method with the appropriate options bag
371    * containing unit as a value. This will be called twice for each element of
372    * validSingularUnits, once with singular and once with plural, and the
373    * results of each pair should be the same (whether a Temporal object or a
374    * primitive value.)
375    */
376   checkPluralUnitsAccepted(func, validSingularUnits) {
377     const plurals = {
378       year: 'years',
379       month: 'months',
380       week: 'weeks',
381       day: 'days',
382       hour: 'hours',
383       minute: 'minutes',
384       second: 'seconds',
385       millisecond: 'milliseconds',
386       microsecond: 'microseconds',
387       nanosecond: 'nanoseconds',
388     };
390     validSingularUnits.forEach((unit) => {
391       const singularValue = func(unit);
392       const pluralValue = func(plurals[unit]);
393       const desc = `Plural ${plurals[unit]} produces the same result as singular ${unit}`;
394       if (singularValue instanceof Temporal.Duration) {
395         TemporalHelpers.assertDurationsEqual(pluralValue, singularValue, desc);
396       } else if (singularValue instanceof Temporal.Instant) {
397         TemporalHelpers.assertInstantsEqual(pluralValue, singularValue, desc);
398       } else if (singularValue instanceof Temporal.PlainDateTime) {
399         TemporalHelpers.assertPlainDateTimesEqual(pluralValue, singularValue, desc);
400       } else if (singularValue instanceof Temporal.PlainTime) {
401         TemporalHelpers.assertPlainTimesEqual(pluralValue, singularValue, desc);
402       } else if (singularValue instanceof Temporal.ZonedDateTime) {
403         TemporalHelpers.assertZonedDateTimesEqual(pluralValue, singularValue, desc);
404       } else {
405         assert.sameValue(pluralValue, singularValue);
406       }
407     });
408   },
410   /*
411    * checkRoundingIncrementOptionWrongType(checkFunc, assertTrueResultFunc, assertObjectResultFunc):
412    *
413    * Checks the type handling of the roundingIncrement option.
414    * checkFunc(roundingIncrement) is a function which takes the value of
415    * roundingIncrement to test, and calls the method under test with it,
416    * returning the result. assertTrueResultFunc(result, description) should
417    * assert that result is the expected result with roundingIncrement: true, and
418    * assertObjectResultFunc(result, description) should assert that result is
419    * the expected result with roundingIncrement being an object with a valueOf()
420    * method.
421    */
422   checkRoundingIncrementOptionWrongType(checkFunc, assertTrueResultFunc, assertObjectResultFunc) {
423     // null converts to 0, which is out of range
424     assert.throws(RangeError, () => checkFunc(null), "null");
425     // Booleans convert to either 0 or 1, and 1 is allowed
426     const trueResult = checkFunc(true);
427     assertTrueResultFunc(trueResult, "true");
428     assert.throws(RangeError, () => checkFunc(false), "false");
429     // Symbols and BigInts cannot convert to numbers
430     assert.throws(TypeError, () => checkFunc(Symbol()), "symbol");
431     assert.throws(TypeError, () => checkFunc(2n), "bigint");
433     // Objects prefer their valueOf() methods when converting to a number
434     assert.throws(RangeError, () => checkFunc({}), "plain object");
436     const expected = [
437       "get roundingIncrement.valueOf",
438       "call roundingIncrement.valueOf",
439     ];
440     const actual = [];
441     const observer = TemporalHelpers.toPrimitiveObserver(actual, 2, "roundingIncrement");
442     const objectResult = checkFunc(observer);
443     assertObjectResultFunc(objectResult, "object with valueOf");
444     assert.compareArray(actual, expected, "order of operations");
445   },
447   /*
448    * checkStringOptionWrongType(propertyName, value, checkFunc, assertFunc):
449    *
450    * Checks the type handling of a string option, of which there are several in
451    * Temporal.
452    * propertyName is the name of the option, and value is the value that
453    * assertFunc should expect it to have.
454    * checkFunc(value) is a function which takes the value of the option to test,
455    * and calls the method under test with it, returning the result.
456    * assertFunc(result, description) should assert that result is the expected
457    * result with the option value being an object with a toString() method
458    * which returns the given value.
459    */
460   checkStringOptionWrongType(propertyName, value, checkFunc, assertFunc) {
461     // null converts to the string "null", which is an invalid string value
462     assert.throws(RangeError, () => checkFunc(null), "null");
463     // Booleans convert to the strings "true" or "false", which are invalid
464     assert.throws(RangeError, () => checkFunc(true), "true");
465     assert.throws(RangeError, () => checkFunc(false), "false");
466     // Symbols cannot convert to strings
467     assert.throws(TypeError, () => checkFunc(Symbol()), "symbol");
468     // Numbers convert to strings which are invalid
469     assert.throws(RangeError, () => checkFunc(2), "number");
470     // BigInts convert to strings which are invalid
471     assert.throws(RangeError, () => checkFunc(2n), "bigint");
473     // Objects prefer their toString() methods when converting to a string
474     assert.throws(RangeError, () => checkFunc({}), "plain object");
476     const expected = [
477       `get ${propertyName}.toString`,
478       `call ${propertyName}.toString`,
479     ];
480     const actual = [];
481     const observer = TemporalHelpers.toPrimitiveObserver(actual, value, propertyName);
482     const result = checkFunc(observer);
483     assertFunc(result, "object with toString");
484     assert.compareArray(actual, expected, "order of operations");
485   },
487   /*
488    * checkSubclassingIgnored(construct, constructArgs, method, methodArgs,
489    *   resultAssertions):
490    *
491    * Methods of Temporal classes that return a new instance of the same class,
492    * must not take the constructor of a subclass into account, nor the @@species
493    * property. This helper runs tests to ensure this.
494    *
495    * construct(...constructArgs) must yield a valid instance of the Temporal
496    * class. instance[method](...methodArgs) is the method call under test, which
497    * must also yield a valid instance of the same Temporal class, not a
498    * subclass. See below for the individual tests that this runs.
499    * resultAssertions() is a function that performs additional assertions on the
500    * instance returned by the method under test.
501    */
502   checkSubclassingIgnored(...args) {
503     this.checkSubclassConstructorNotObject(...args);
504     this.checkSubclassConstructorUndefined(...args);
505     this.checkSubclassConstructorThrows(...args);
506     this.checkSubclassConstructorNotCalled(...args);
507     this.checkSubclassSpeciesInvalidResult(...args);
508     this.checkSubclassSpeciesNotAConstructor(...args);
509     this.checkSubclassSpeciesNull(...args);
510     this.checkSubclassSpeciesUndefined(...args);
511     this.checkSubclassSpeciesThrows(...args);
512   },
514   /*
515    * Checks that replacing the 'constructor' property of the instance with
516    * various primitive values does not affect the returned new instance.
517    */
518   checkSubclassConstructorNotObject(construct, constructArgs, method, methodArgs, resultAssertions) {
519     function check(value, description) {
520       const instance = new construct(...constructArgs);
521       instance.constructor = value;
522       const result = instance[method](...methodArgs);
523       assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description);
524       resultAssertions(result);
525     }
527     check(null, "null");
528     check(true, "true");
529     check("test", "string");
530     check(Symbol(), "Symbol");
531     check(7, "number");
532     check(7n, "bigint");
533   },
535   /*
536    * Checks that replacing the 'constructor' property of the subclass with
537    * undefined does not affect the returned new instance.
538    */
539   checkSubclassConstructorUndefined(construct, constructArgs, method, methodArgs, resultAssertions) {
540     let called = 0;
542     class MySubclass extends construct {
543       constructor() {
544         ++called;
545         super(...constructArgs);
546       }
547     }
549     const instance = new MySubclass();
550     assert.sameValue(called, 1);
552     MySubclass.prototype.constructor = undefined;
554     const result = instance[method](...methodArgs);
555     assert.sameValue(called, 1);
556     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
557     resultAssertions(result);
558   },
560   /*
561    * Checks that making the 'constructor' property of the instance throw when
562    * called does not affect the returned new instance.
563    */
564   checkSubclassConstructorThrows(construct, constructArgs, method, methodArgs, resultAssertions) {
565     function CustomError() {}
566     const instance = new construct(...constructArgs);
567     Object.defineProperty(instance, "constructor", {
568       get() {
569         throw new CustomError();
570       }
571     });
572     const result = instance[method](...methodArgs);
573     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
574     resultAssertions(result);
575   },
577   /*
578    * Checks that when subclassing, the subclass constructor is not called by
579    * the method under test.
580    */
581   checkSubclassConstructorNotCalled(construct, constructArgs, method, methodArgs, resultAssertions) {
582     let called = 0;
584     class MySubclass extends construct {
585       constructor() {
586         ++called;
587         super(...constructArgs);
588       }
589     }
591     const instance = new MySubclass();
592     assert.sameValue(called, 1);
594     const result = instance[method](...methodArgs);
595     assert.sameValue(called, 1);
596     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
597     resultAssertions(result);
598   },
600   /*
601    * Check that the constructor's @@species property is ignored when it's a
602    * constructor that returns a non-object value.
603    */
604   checkSubclassSpeciesInvalidResult(construct, constructArgs, method, methodArgs, resultAssertions) {
605     function check(value, description) {
606       const instance = new construct(...constructArgs);
607       instance.constructor = {
608         [Symbol.species]: function() {
609           return value;
610         },
611       };
612       const result = instance[method](...methodArgs);
613       assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description);
614       resultAssertions(result);
615     }
617     check(undefined, "undefined");
618     check(null, "null");
619     check(true, "true");
620     check("test", "string");
621     check(Symbol(), "Symbol");
622     check(7, "number");
623     check(7n, "bigint");
624     check({}, "plain object");
625   },
627   /*
628    * Check that the constructor's @@species property is ignored when it's not a
629    * constructor.
630    */
631   checkSubclassSpeciesNotAConstructor(construct, constructArgs, method, methodArgs, resultAssertions) {
632     function check(value, description) {
633       const instance = new construct(...constructArgs);
634       instance.constructor = {
635         [Symbol.species]: value,
636       };
637       const result = instance[method](...methodArgs);
638       assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description);
639       resultAssertions(result);
640     }
642     check(true, "true");
643     check("test", "string");
644     check(Symbol(), "Symbol");
645     check(7, "number");
646     check(7n, "bigint");
647     check({}, "plain object");
648   },
650   /*
651    * Check that the constructor's @@species property is ignored when it's null.
652    */
653   checkSubclassSpeciesNull(construct, constructArgs, method, methodArgs, resultAssertions) {
654     let called = 0;
656     class MySubclass extends construct {
657       constructor() {
658         ++called;
659         super(...constructArgs);
660       }
661     }
663     const instance = new MySubclass();
664     assert.sameValue(called, 1);
666     MySubclass.prototype.constructor = {
667       [Symbol.species]: null,
668     };
670     const result = instance[method](...methodArgs);
671     assert.sameValue(called, 1);
672     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
673     resultAssertions(result);
674   },
676   /*
677    * Check that the constructor's @@species property is ignored when it's
678    * undefined.
679    */
680   checkSubclassSpeciesUndefined(construct, constructArgs, method, methodArgs, resultAssertions) {
681     let called = 0;
683     class MySubclass extends construct {
684       constructor() {
685         ++called;
686         super(...constructArgs);
687       }
688     }
690     const instance = new MySubclass();
691     assert.sameValue(called, 1);
693     MySubclass.prototype.constructor = {
694       [Symbol.species]: undefined,
695     };
697     const result = instance[method](...methodArgs);
698     assert.sameValue(called, 1);
699     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
700     resultAssertions(result);
701   },
703   /*
704    * Check that the constructor's @@species property is ignored when it throws,
705    * i.e. it is not called at all.
706    */
707   checkSubclassSpeciesThrows(construct, constructArgs, method, methodArgs, resultAssertions) {
708     function CustomError() {}
710     const instance = new construct(...constructArgs);
711     instance.constructor = {
712       get [Symbol.species]() {
713         throw new CustomError();
714       },
715     };
717     const result = instance[method](...methodArgs);
718     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
719   },
721   /*
722    * checkSubclassingIgnoredStatic(construct, method, methodArgs, resultAssertions):
723    *
724    * Static methods of Temporal classes that return a new instance of the class,
725    * must not use the this-value as a constructor. This helper runs tests to
726    * ensure this.
727    *
728    * construct[method](...methodArgs) is the static method call under test, and
729    * must yield a valid instance of the Temporal class, not a subclass. See
730    * below for the individual tests that this runs.
731    * resultAssertions() is a function that performs additional assertions on the
732    * instance returned by the method under test.
733    */
734   checkSubclassingIgnoredStatic(...args) {
735     this.checkStaticInvalidReceiver(...args);
736     this.checkStaticReceiverNotCalled(...args);
737     this.checkThisValueNotCalled(...args);
738   },
740   /*
741    * Check that calling the static method with a receiver that's not callable,
742    * still calls the intrinsic constructor.
743    */
744   checkStaticInvalidReceiver(construct, method, methodArgs, resultAssertions) {
745     function check(value, description) {
746       const result = construct[method].apply(value, methodArgs);
747       assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
748       resultAssertions(result);
749     }
751     check(undefined, "undefined");
752     check(null, "null");
753     check(true, "true");
754     check("test", "string");
755     check(Symbol(), "symbol");
756     check(7, "number");
757     check(7n, "bigint");
758     check({}, "Non-callable object");
759   },
761   /*
762    * Check that calling the static method with a receiver that returns a value
763    * that's not callable, still calls the intrinsic constructor.
764    */
765   checkStaticReceiverNotCalled(construct, method, methodArgs, resultAssertions) {
766     function check(value, description) {
767       const receiver = function () {
768         return value;
769       };
770       const result = construct[method].apply(receiver, methodArgs);
771       assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
772       resultAssertions(result);
773     }
775     check(undefined, "undefined");
776     check(null, "null");
777     check(true, "true");
778     check("test", "string");
779     check(Symbol(), "symbol");
780     check(7, "number");
781     check(7n, "bigint");
782     check({}, "Non-callable object");
783   },
785   /*
786    * Check that the receiver isn't called.
787    */
788   checkThisValueNotCalled(construct, method, methodArgs, resultAssertions) {
789     let called = false;
791     class MySubclass extends construct {
792       constructor(...args) {
793         called = true;
794         super(...args);
795       }
796     }
798     const result = MySubclass[method](...methodArgs);
799     assert.sameValue(called, false);
800     assert.sameValue(Object.getPrototypeOf(result), construct.prototype);
801     resultAssertions(result);
802   },
804   /*
805    * Check that any iterable returned from a custom time zone's
806    * getPossibleInstantsFor() method is exhausted.
807    * The custom time zone object is passed in to func().
808    * expected is an array of strings representing the expected calls to the
809    * getPossibleInstantsFor() method. The PlainDateTimes that it is called with,
810    * are compared (using their toString() results) with the array.
811    */
812   checkTimeZonePossibleInstantsIterable(func, expected) {
813     // A custom time zone that returns an iterable instead of an array from its
814     // getPossibleInstantsFor() method, and for testing purposes skips
815     // 00:00-01:00 UTC on January 1, 2030, and repeats 00:00-01:00 UTC+1 on
816     // January 3, 2030. Otherwise identical to the UTC time zone.
817     class TimeZonePossibleInstantsIterable extends Temporal.TimeZone {
818       constructor() {
819         super("UTC");
820         this.getPossibleInstantsForCallCount = 0;
821         this.getPossibleInstantsForCalledWith = [];
822         this.getPossibleInstantsForReturns = [];
823         this.iteratorExhausted = [];
824       }
826       toString() {
827         return "Custom/Iterable";
828       }
830       getOffsetNanosecondsFor(instant) {
831         if (Temporal.Instant.compare(instant, "2030-01-01T00:00Z") >= 0 &&
832           Temporal.Instant.compare(instant, "2030-01-03T01:00Z") < 0) {
833           return 3600_000_000_000;
834         } else {
835           return 0;
836         }
837       }
839       getPossibleInstantsFor(dateTime) {
840         this.getPossibleInstantsForCallCount++;
841         this.getPossibleInstantsForCalledWith.push(dateTime);
843         // Fake DST transition
844         let retval = super.getPossibleInstantsFor(dateTime);
845         if (dateTime.toPlainDate().equals("2030-01-01") && dateTime.hour === 0) {
846           retval = [];
847         } else if (dateTime.toPlainDate().equals("2030-01-03") && dateTime.hour === 0) {
848           retval.push(retval[0].subtract({ hours: 1 }));
849         } else if (dateTime.year === 2030 && dateTime.month === 1 && dateTime.day >= 1 && dateTime.day <= 2) {
850           retval[0] = retval[0].subtract({ hours: 1 });
851         }
853         this.getPossibleInstantsForReturns.push(retval);
854         this.iteratorExhausted.push(false);
855         return {
856           callIndex: this.getPossibleInstantsForCallCount - 1,
857           timeZone: this,
858           *[Symbol.iterator]() {
859             yield* this.timeZone.getPossibleInstantsForReturns[this.callIndex];
860             this.timeZone.iteratorExhausted[this.callIndex] = true;
861           },
862         };
863       }
864     }
866     const timeZone = new TimeZonePossibleInstantsIterable();
867     func(timeZone);
869     assert.sameValue(timeZone.getPossibleInstantsForCallCount, expected.length, "getPossibleInstantsFor() method called correct number of times");
871     for (let index = 0; index < expected.length; index++) {
872       assert.sameValue(timeZone.getPossibleInstantsForCalledWith[index].toString(), expected[index], "getPossibleInstantsFor() called with expected PlainDateTime");
873       assert(timeZone.iteratorExhausted[index], "iterated through the whole iterable");
874     }
875   },
877   /*
878    * Check that any calendar-carrying Temporal object has its [[Calendar]]
879    * internal slot read by ToTemporalCalendar, and does not fetch the calendar
880    * by calling getters.
881    * The custom calendar object is passed in to func() so that it can do its
882    * own additional assertions involving the calendar if necessary. (Sometimes
883    * there is nothing to assert as the calendar isn't stored anywhere that can
884    * be asserted about.)
885    */
886   checkToTemporalCalendarFastPath(func) {
887     class CalendarFastPathCheck extends Temporal.Calendar {
888       constructor() {
889         super("iso8601");
890       }
892       dateFromFields(...args) {
893         return super.dateFromFields(...args).withCalendar(this);
894       }
896       monthDayFromFields(...args) {
897         const { isoYear, isoMonth, isoDay } = super.monthDayFromFields(...args).getISOFields();
898         return new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear);
899       }
901       yearMonthFromFields(...args) {
902         const { isoYear, isoMonth, isoDay } = super.yearMonthFromFields(...args).getISOFields();
903         return new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay);
904       }
906       toString() {
907         return "fast-path-check";
908       }
909     }
910     const calendar = new CalendarFastPathCheck();
912     const plainDate = new Temporal.PlainDate(2000, 5, 2, calendar);
913     const plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar);
914     const plainMonthDay = new Temporal.PlainMonthDay(5, 2, calendar);
915     const plainYearMonth = new Temporal.PlainYearMonth(2000, 5, calendar);
916     const zonedDateTime = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar);
918     [plainDate, plainDateTime, plainMonthDay, plainYearMonth, zonedDateTime].forEach((temporalObject) => {
919       const actual = [];
920       const expected = [];
922       Object.defineProperty(temporalObject, "calendar", {
923         get() {
924           actual.push("get calendar");
925           return calendar;
926         },
927       });
929       func(temporalObject, calendar);
930       assert.compareArray(actual, expected, "calendar getter not called");
931     });
932   },
934   checkToTemporalInstantFastPath(func) {
935     const actual = [];
936     const expected = [];
938     const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC");
939     Object.defineProperty(datetime, 'toString', {
940       get() {
941         actual.push("get toString");
942         return function (options) {
943           actual.push("call toString");
944           return Temporal.ZonedDateTime.prototype.toString.call(this, options);
945         };
946       },
947     });
949     func(datetime);
950     assert.compareArray(actual, expected, "toString not called");
951   },
953   checkToTemporalPlainDateTimeFastPath(func) {
954     const actual = [];
955     const expected = [];
957     const calendar = new Temporal.Calendar("iso8601");
958     const date = new Temporal.PlainDate(2000, 5, 2, calendar);
959     const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.PlainDate.prototype);
960     ["year", "month", "monthCode", "day"].forEach((property) => {
961       Object.defineProperty(date, property, {
962         get() {
963           actual.push(`get ${formatPropertyName(property)}`);
964           const value = prototypeDescrs[property].get.call(this);
965           return TemporalHelpers.toPrimitiveObserver(actual, value, property);
966         },
967       });
968     });
969     ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].forEach((property) => {
970       Object.defineProperty(date, property, {
971         get() {
972           actual.push(`get ${formatPropertyName(property)}`);
973           return undefined;
974         },
975       });
976     });
977     Object.defineProperty(date, "calendar", {
978       get() {
979         actual.push("get calendar");
980         return calendar;
981       },
982     });
984     func(date, calendar);
985     assert.compareArray(actual, expected, "property getters not called");
986   },
988   /*
989    * A custom calendar used in prototype pollution checks. Verifies that the
990    * fromFields methods are always called with a null-prototype fields object.
991    */
992   calendarCheckFieldsPrototypePollution() {
993     class CalendarCheckFieldsPrototypePollution extends Temporal.Calendar {
994       constructor() {
995         super("iso8601");
996         this.dateFromFieldsCallCount = 0;
997         this.yearMonthFromFieldsCallCount = 0;
998         this.monthDayFromFieldsCallCount = 0;
999       }
1001       // toString must remain "iso8601", so that some methods don't throw due to
1002       // incompatible calendars
1004       dateFromFields(fields, options = {}) {
1005         this.dateFromFieldsCallCount++;
1006         assert.sameValue(Object.getPrototypeOf(fields), null, "dateFromFields should be called with null-prototype fields object");
1007         return super.dateFromFields(fields, options);
1008       }
1010       yearMonthFromFields(fields, options = {}) {
1011         this.yearMonthFromFieldsCallCount++;
1012         assert.sameValue(Object.getPrototypeOf(fields), null, "yearMonthFromFields should be called with null-prototype fields object");
1013         return super.yearMonthFromFields(fields, options);
1014       }
1016       monthDayFromFields(fields, options = {}) {
1017         this.monthDayFromFieldsCallCount++;
1018         assert.sameValue(Object.getPrototypeOf(fields), null, "monthDayFromFields should be called with null-prototype fields object");
1019         return super.monthDayFromFields(fields, options);
1020       }
1021     }
1023     return new CalendarCheckFieldsPrototypePollution();
1024   },
1026   /*
1027    * A custom calendar used in prototype pollution checks. Verifies that the
1028    * mergeFields() method is always called with null-prototype fields objects.
1029    */
1030   calendarCheckMergeFieldsPrototypePollution() {
1031     class CalendarCheckMergeFieldsPrototypePollution extends Temporal.Calendar {
1032       constructor() {
1033         super("iso8601");
1034         this.mergeFieldsCallCount = 0;
1035       }
1037       toString() {
1038         return "merge-fields-null-proto";
1039       }
1041       mergeFields(fields, additionalFields) {
1042         this.mergeFieldsCallCount++;
1043         assert.sameValue(Object.getPrototypeOf(fields), null, "mergeFields should be called with null-prototype fields object (first argument)");
1044         assert.sameValue(Object.getPrototypeOf(additionalFields), null, "mergeFields should be called with null-prototype fields object (second argument)");
1045         return super.mergeFields(fields, additionalFields);
1046       }
1047     }
1049     return new CalendarCheckMergeFieldsPrototypePollution();
1050   },
1052   /*
1053    * A custom calendar used in prototype pollution checks. Verifies that methods
1054    * are always called with a null-prototype options object.
1055    */
1056   calendarCheckOptionsPrototypePollution() {
1057     class CalendarCheckOptionsPrototypePollution extends Temporal.Calendar {
1058       constructor() {
1059         super("iso8601");
1060         this.yearMonthFromFieldsCallCount = 0;
1061         this.dateUntilCallCount = 0;
1062       }
1064       toString() {
1065         return "options-null-proto";
1066       }
1068       yearMonthFromFields(fields, options) {
1069         this.yearMonthFromFieldsCallCount++;
1070         assert.sameValue(Object.getPrototypeOf(options), null, "yearMonthFromFields should be called with null-prototype options");
1071         return super.yearMonthFromFields(fields, options);
1072       }
1074       dateUntil(one, two, options) {
1075         this.dateUntilCallCount++;
1076         assert.sameValue(Object.getPrototypeOf(options), null, "dateUntil should be called with null-prototype options");
1077         return super.dateUntil(one, two, options);
1078       }
1079     }
1081     return new CalendarCheckOptionsPrototypePollution();
1082   },
1084   /*
1085    * A custom calendar that asserts its dateAdd() method is called with the
1086    * options parameter having the value undefined.
1087    */
1088   calendarDateAddUndefinedOptions() {
1089     class CalendarDateAddUndefinedOptions extends Temporal.Calendar {
1090       constructor() {
1091         super("iso8601");
1092         this.dateAddCallCount = 0;
1093       }
1095       toString() {
1096         return "dateadd-undef-options";
1097       }
1099       dateAdd(date, duration, options) {
1100         this.dateAddCallCount++;
1101         assert.sameValue(options, undefined, "dateAdd shouldn't be called with options");
1102         return super.dateAdd(date, duration, options);
1103       }
1104     }
1105     return new CalendarDateAddUndefinedOptions();
1106   },
1108   /*
1109    * A custom calendar that asserts its dateAdd() method is called with a
1110    * PlainDate instance. Optionally, it also asserts that the PlainDate instance
1111    * is the specific object `this.specificPlainDate`, if it is set by the
1112    * calling code.
1113    */
1114   calendarDateAddPlainDateInstance() {
1115     class CalendarDateAddPlainDateInstance extends Temporal.Calendar {
1116       constructor() {
1117         super("iso8601");
1118         this.dateAddCallCount = 0;
1119         this.specificPlainDate = undefined;
1120       }
1122       toString() {
1123         return "dateadd-plain-date-instance";
1124       }
1126       dateFromFields(...args) {
1127         return super.dateFromFields(...args).withCalendar(this);
1128       }
1130       dateAdd(date, duration, options) {
1131         this.dateAddCallCount++;
1132         assert(date instanceof Temporal.PlainDate, "dateAdd() should be called with a PlainDate instance");
1133         if (this.dateAddCallCount === 1 && this.specificPlainDate) {
1134           assert.sameValue(date, this.specificPlainDate, `dateAdd() should be called first with the specific PlainDate instance ${this.specificPlainDate}`);
1135         }
1136         return super.dateAdd(date, duration, options).withCalendar(this);
1137       }
1138     }
1139     return new CalendarDateAddPlainDateInstance();
1140   },
1142   /*
1143    * A custom calendar that returns an iterable instead of an array from its
1144    * fields() method, otherwise identical to the ISO calendar.
1145    */
1146   calendarFieldsIterable() {
1147     class CalendarFieldsIterable extends Temporal.Calendar {
1148       constructor() {
1149         super("iso8601");
1150         this.fieldsCallCount = 0;
1151         this.fieldsCalledWith = [];
1152         this.iteratorExhausted = [];
1153       }
1155       toString() {
1156         return "fields-iterable";
1157       }
1159       fields(fieldNames) {
1160         this.fieldsCallCount++;
1161         this.fieldsCalledWith.push(fieldNames.slice());
1162         this.iteratorExhausted.push(false);
1163         return {
1164           callIndex: this.fieldsCallCount - 1,
1165           calendar: this,
1166           *[Symbol.iterator]() {
1167             yield* this.calendar.fieldsCalledWith[this.callIndex];
1168             this.calendar.iteratorExhausted[this.callIndex] = true;
1169           },
1170         };
1171       }
1172     }
1173     return new CalendarFieldsIterable();
1174   },
1176   /*
1177    * A custom calendar that asserts its ...FromFields() methods are called with
1178    * the options parameter having the value undefined.
1179    */
1180   calendarFromFieldsUndefinedOptions() {
1181     class CalendarFromFieldsUndefinedOptions extends Temporal.Calendar {
1182       constructor() {
1183         super("iso8601");
1184         this.dateFromFieldsCallCount = 0;
1185         this.monthDayFromFieldsCallCount = 0;
1186         this.yearMonthFromFieldsCallCount = 0;
1187       }
1189       toString() {
1190         return "from-fields-undef-options";
1191       }
1193       dateFromFields(fields, options) {
1194         this.dateFromFieldsCallCount++;
1195         assert.sameValue(options, undefined, "dateFromFields shouldn't be called with options");
1196         return super.dateFromFields(fields, options);
1197       }
1199       yearMonthFromFields(fields, options) {
1200         this.yearMonthFromFieldsCallCount++;
1201         assert.sameValue(options, undefined, "yearMonthFromFields shouldn't be called with options");
1202         return super.yearMonthFromFields(fields, options);
1203       }
1205       monthDayFromFields(fields, options) {
1206         this.monthDayFromFieldsCallCount++;
1207         assert.sameValue(options, undefined, "monthDayFromFields shouldn't be called with options");
1208         return super.monthDayFromFields(fields, options);
1209       }
1210     }
1211     return new CalendarFromFieldsUndefinedOptions();
1212   },
1214   /*
1215    * A custom calendar that modifies the fields object passed in to
1216    * dateFromFields, sabotaging its time properties.
1217    */
1218   calendarMakeInfinityTime() {
1219     class CalendarMakeInfinityTime extends Temporal.Calendar {
1220       constructor() {
1221         super("iso8601");
1222       }
1224       dateFromFields(fields, options) {
1225         const retval = super.dateFromFields(fields, options);
1226         fields.hour = Infinity;
1227         fields.minute = Infinity;
1228         fields.second = Infinity;
1229         fields.millisecond = Infinity;
1230         fields.microsecond = Infinity;
1231         fields.nanosecond = Infinity;
1232         return retval;
1233       }
1234     }
1235     return new CalendarMakeInfinityTime();
1236   },
1238   /*
1239    * A custom calendar that defines getters on the fields object passed into
1240    * dateFromFields that throw, sabotaging its time properties.
1241    */
1242   calendarMakeInvalidGettersTime() {
1243     class CalendarMakeInvalidGettersTime extends Temporal.Calendar {
1244       constructor() {
1245         super("iso8601");
1246       }
1248       dateFromFields(fields, options) {
1249         const retval = super.dateFromFields(fields, options);
1250         const throwingDescriptor = {
1251           get() {
1252             throw new Test262Error("reading a sabotaged time field");
1253           },
1254         };
1255         Object.defineProperties(fields, {
1256           hour: throwingDescriptor,
1257           minute: throwingDescriptor,
1258           second: throwingDescriptor,
1259           millisecond: throwingDescriptor,
1260           microsecond: throwingDescriptor,
1261           nanosecond: throwingDescriptor,
1262         });
1263         return retval;
1264       }
1265     }
1266     return new CalendarMakeInvalidGettersTime();
1267   },
1269   /*
1270    * A custom calendar whose mergeFields() method returns a proxy object with
1271    * all of its Get and HasProperty operations observable, as well as adding a
1272    * "shouldNotBeCopied": true property.
1273    */
1274   calendarMergeFieldsGetters() {
1275     class CalendarMergeFieldsGetters extends Temporal.Calendar {
1276       constructor() {
1277         super("iso8601");
1278         this.mergeFieldsReturnOperations = [];
1279       }
1281       toString() {
1282         return "merge-fields-getters";
1283       }
1285       dateFromFields(fields, options) {
1286         assert.sameValue(fields.shouldNotBeCopied, undefined, "extra fields should not be copied");
1287         return super.dateFromFields(fields, options);
1288       }
1290       yearMonthFromFields(fields, options) {
1291         assert.sameValue(fields.shouldNotBeCopied, undefined, "extra fields should not be copied");
1292         return super.yearMonthFromFields(fields, options);
1293       }
1295       monthDayFromFields(fields, options) {
1296         assert.sameValue(fields.shouldNotBeCopied, undefined, "extra fields should not be copied");
1297         return super.monthDayFromFields(fields, options);
1298       }
1300       mergeFields(fields, additionalFields) {
1301         const retval = super.mergeFields(fields, additionalFields);
1302         retval._calendar = this;
1303         retval.shouldNotBeCopied = true;
1304         return new Proxy(retval, {
1305           get(target, key) {
1306             target._calendar.mergeFieldsReturnOperations.push(`get ${key}`);
1307             const result = target[key];
1308             if (result === undefined) {
1309               return undefined;
1310             }
1311             return TemporalHelpers.toPrimitiveObserver(target._calendar.mergeFieldsReturnOperations, result, key);
1312           },
1313           has(target, key) {
1314             target._calendar.mergeFieldsReturnOperations.push(`has ${key}`);
1315             return key in target;
1316           },
1317         });
1318       }
1319     }
1320     return new CalendarMergeFieldsGetters();
1321   },
1323   /*
1324    * A custom calendar whose mergeFields() method returns a primitive value,
1325    * given by @primitive, and which records the number of calls made to its
1326    * dateFromFields(), yearMonthFromFields(), and monthDayFromFields() methods.
1327    */
1328   calendarMergeFieldsReturnsPrimitive(primitive) {
1329     class CalendarMergeFieldsPrimitive extends Temporal.Calendar {
1330       constructor(mergeFieldsReturnValue) {
1331         super("iso8601");
1332         this._mergeFieldsReturnValue = mergeFieldsReturnValue;
1333         this.dateFromFieldsCallCount = 0;
1334         this.monthDayFromFieldsCallCount = 0;
1335         this.yearMonthFromFieldsCallCount = 0;
1336       }
1338       toString() {
1339         return "merge-fields-primitive";
1340       }
1342       dateFromFields(fields, options) {
1343         this.dateFromFieldsCallCount++;
1344         return super.dateFromFields(fields, options);
1345       }
1347       yearMonthFromFields(fields, options) {
1348         this.yearMonthFromFieldsCallCount++;
1349         return super.yearMonthFromFields(fields, options);
1350       }
1352       monthDayFromFields(fields, options) {
1353         this.monthDayFromFieldsCallCount++;
1354         return super.monthDayFromFields(fields, options);
1355       }
1357       mergeFields() {
1358         return this._mergeFieldsReturnValue;
1359       }
1360     }
1361     return new CalendarMergeFieldsPrimitive(primitive);
1362   },
1364   /*
1365    * A custom calendar whose fields() method returns the same value as the
1366    * iso8601 calendar, with the addition of extraFields provided as parameter.
1367    */
1368   calendarWithExtraFields(fields) {
1369     class CalendarWithExtraFields extends Temporal.Calendar {
1370       constructor(extraFields) {
1371         super("iso8601");
1372         this._extraFields = extraFields;
1373       }
1375       fields(fieldNames) {
1376         return super.fields(fieldNames).concat(this._extraFields);
1377       }
1378     }
1380     return new CalendarWithExtraFields(fields);
1381   },
1383   /*
1384    * crossDateLineTimeZone():
1385    *
1386    * This returns an instance of a custom time zone class that implements one
1387    * single transition where the time zone moves from one side of the
1388    * International Date Line to the other, for the purpose of testing time zone
1389    * calculations without depending on system time zone data.
1390    *
1391    * The transition occurs at epoch second 1325239200 and goes from offset
1392    * -10:00 to +14:00. In other words, the time zone skips the whole calendar
1393    * day of 2011-12-30. This is the same as the real-life transition in the
1394    * Pacific/Apia time zone.
1395    */
1396   crossDateLineTimeZone() {
1397     const { compare } = Temporal.PlainDateTime;
1398     const skippedDay = new Temporal.PlainDate(2011, 12, 30);
1399     const transitionEpoch = 1325239200_000_000_000n;
1400     const beforeOffset = new Temporal.TimeZone("-10:00");
1401     const afterOffset = new Temporal.TimeZone("+14:00");
1403     class CrossDateLineTimeZone extends Temporal.TimeZone {
1404       constructor() {
1405         super("+14:00");
1406       }
1408       getOffsetNanosecondsFor(instant) {
1409         if (instant.epochNanoseconds < transitionEpoch) {
1410           return beforeOffset.getOffsetNanosecondsFor(instant);
1411         }
1412         return afterOffset.getOffsetNanosecondsFor(instant);
1413       }
1415       getPossibleInstantsFor(datetime) {
1416         const comparison = Temporal.PlainDate.compare(datetime.toPlainDate(), skippedDay);
1417         if (comparison === 0) {
1418           return [];
1419         }
1420         if (comparison < 0) {
1421           return [beforeOffset.getInstantFor(datetime)];
1422         }
1423         return [afterOffset.getInstantFor(datetime)];
1424       }
1426       getPreviousTransition(instant) {
1427         if (instant.epochNanoseconds > transitionEpoch) return new Temporal.Instant(transitionEpoch);
1428         return null;
1429       }
1431       getNextTransition(instant) {
1432         if (instant.epochNanoseconds < transitionEpoch) return new Temporal.Instant(transitionEpoch);
1433         return null;
1434       }
1436       toString() {
1437         return "Custom/Date_Line";
1438       }
1439     }
1440     return new CrossDateLineTimeZone();
1441   },
1443   /*
1444    * observeProperty(calls, object, propertyName, value):
1445    *
1446    * Defines an own property @object.@propertyName with value @value, that
1447    * will log any calls to its accessors to the array @calls.
1448    */
1449   observeProperty(calls, object, propertyName, value, objectName = "") {
1450     Object.defineProperty(object, propertyName, {
1451       get() {
1452         calls.push(`get ${formatPropertyName(propertyName, objectName)}`);
1453         return value;
1454       },
1455       set(v) {
1456         calls.push(`set ${formatPropertyName(propertyName, objectName)}`);
1457       }
1458     });
1459   },
1461   /*
1462    * observeMethod(calls, object, propertyName, value):
1463    *
1464    * Defines an own property @object.@propertyName with value @value, that
1465    * will log any calls of @value to the array @calls.
1466    */
1467   observeMethod(calls, object, propertyName, objectName = "") {
1468     const method = object[propertyName];
1469     object[propertyName] = function () {
1470       calls.push(`call ${formatPropertyName(propertyName, objectName)}`);
1471       return method.apply(object, arguments);
1472     };
1473   },
1475   /*
1476    * Used for substituteMethod to indicate default behavior instead of a
1477    * substituted value
1478    */
1479   SUBSTITUTE_SKIP: SKIP_SYMBOL,
1481   /*
1482    * substituteMethod(object, propertyName, values):
1483    *
1484    * Defines an own property @object.@propertyName that will, for each
1485    * subsequent call to the method previously defined as
1486    * @object.@propertyName:
1487    *  - Call the method, if no more values remain
1488    *  - Call the method, if the value in @values for the corresponding call
1489    *    is SUBSTITUTE_SKIP
1490    *  - Otherwise, return the corresponding value in @value
1491    */
1492   substituteMethod(object, propertyName, values) {
1493     let calls = 0;
1494     const method = object[propertyName];
1495     object[propertyName] = function () {
1496       if (calls >= values.length) {
1497         return method.apply(object, arguments);
1498       } else if (values[calls] === SKIP_SYMBOL) {
1499         calls++;
1500         return method.apply(object, arguments);
1501       } else {
1502         return values[calls++];
1503       }
1504     };
1505   },
1507   /*
1508    * calendarObserver:
1509    * A custom calendar that behaves exactly like the ISO 8601 calendar but
1510    * tracks calls to any of its methods, and Get/Has operations on its
1511    * properties, by appending messages to an array. This is for the purpose of
1512    * testing order of operations that are observable from user code.
1513    * objectName is used in the log.
1514    */
1515   calendarObserver(calls, objectName, methodOverrides = {}) {
1516     function removeExtraHasPropertyChecks(objectName, calls) {
1517       // Inserting the tracking calendar into the return values of methods
1518       // that we chain up into the ISO calendar for, causes extra HasProperty
1519       // checks, which we observe. This removes them so that we don't leak
1520       // implementation details of the helper into the test code.
1521       assert.sameValue(calls.pop(), `has ${objectName}.yearOfWeek`);
1522       assert.sameValue(calls.pop(), `has ${objectName}.yearMonthFromFields`);
1523       assert.sameValue(calls.pop(), `has ${objectName}.year`);
1524       assert.sameValue(calls.pop(), `has ${objectName}.weekOfYear`);
1525       assert.sameValue(calls.pop(), `has ${objectName}.monthsInYear`);
1526       assert.sameValue(calls.pop(), `has ${objectName}.monthDayFromFields`);
1527       assert.sameValue(calls.pop(), `has ${objectName}.monthCode`);
1528       assert.sameValue(calls.pop(), `has ${objectName}.month`);
1529       assert.sameValue(calls.pop(), `has ${objectName}.mergeFields`);
1530       assert.sameValue(calls.pop(), `has ${objectName}.inLeapYear`);
1531       assert.sameValue(calls.pop(), `has ${objectName}.id`);
1532       assert.sameValue(calls.pop(), `has ${objectName}.fields`);
1533       assert.sameValue(calls.pop(), `has ${objectName}.daysInYear`);
1534       assert.sameValue(calls.pop(), `has ${objectName}.daysInWeek`);
1535       assert.sameValue(calls.pop(), `has ${objectName}.daysInMonth`);
1536       assert.sameValue(calls.pop(), `has ${objectName}.dayOfYear`);
1537       assert.sameValue(calls.pop(), `has ${objectName}.dayOfWeek`);
1538       assert.sameValue(calls.pop(), `has ${objectName}.day`);
1539       assert.sameValue(calls.pop(), `has ${objectName}.dateUntil`);
1540       assert.sameValue(calls.pop(), `has ${objectName}.dateFromFields`);
1541       assert.sameValue(calls.pop(), `has ${objectName}.dateAdd`);
1542     }
1544     const iso8601 = new Temporal.Calendar("iso8601");
1545     const trackingMethods = {
1546       dateFromFields(...args) {
1547         calls.push(`call ${objectName}.dateFromFields`);
1548         if ('dateFromFields' in methodOverrides) {
1549           const value = methodOverrides.dateFromFields;
1550           return typeof value === "function" ? value(...args) : value;
1551         }
1552         const originalResult = iso8601.dateFromFields(...args);
1553         // Replace the calendar in the result with the call-tracking calendar
1554         const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
1555         const result = new Temporal.PlainDate(isoYear, isoMonth, isoDay, this);
1556         removeExtraHasPropertyChecks(objectName, calls);
1557         return result;
1558       },
1559       yearMonthFromFields(...args) {
1560         calls.push(`call ${objectName}.yearMonthFromFields`);
1561         if ('yearMonthFromFields' in methodOverrides) {
1562           const value = methodOverrides.yearMonthFromFields;
1563           return typeof value === "function" ? value(...args) : value;
1564         }
1565         const originalResult = iso8601.yearMonthFromFields(...args);
1566         // Replace the calendar in the result with the call-tracking calendar
1567         const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
1568         const result = new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay);
1569         removeExtraHasPropertyChecks(objectName, calls);
1570         return result;
1571       },
1572       monthDayFromFields(...args) {
1573         calls.push(`call ${objectName}.monthDayFromFields`);
1574         if ('monthDayFromFields' in methodOverrides) {
1575           const value = methodOverrides.monthDayFromFields;
1576           return typeof value === "function" ? value(...args) : value;
1577         }
1578         const originalResult = iso8601.monthDayFromFields(...args);
1579         // Replace the calendar in the result with the call-tracking calendar
1580         const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
1581         const result = new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear);
1582         removeExtraHasPropertyChecks(objectName, calls);
1583         return result;
1584       },
1585       dateAdd(...args) {
1586         calls.push(`call ${objectName}.dateAdd`);
1587         if ('dateAdd' in methodOverrides) {
1588           const value = methodOverrides.dateAdd;
1589           return typeof value === "function" ? value(...args) : value;
1590         }
1591         const originalResult = iso8601.dateAdd(...args);
1592         const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
1593         const result = new Temporal.PlainDate(isoYear, isoMonth, isoDay, this);
1594         removeExtraHasPropertyChecks(objectName, calls);
1595         return result;
1596       },
1597       id: "iso8601",
1598     };
1599     // Automatically generate the other methods that don't need any custom code
1600     [
1601       "dateUntil",
1602       "day",
1603       "dayOfWeek",
1604       "dayOfYear",
1605       "daysInMonth",
1606       "daysInWeek",
1607       "daysInYear",
1608       "era",
1609       "eraYear",
1610       "fields",
1611       "inLeapYear",
1612       "mergeFields",
1613       "month",
1614       "monthCode",
1615       "monthsInYear",
1616       "toString",
1617       "weekOfYear",
1618       "year",
1619       "yearOfWeek",
1620     ].forEach((methodName) => {
1621       trackingMethods[methodName] = function (...args) {
1622         calls.push(`call ${formatPropertyName(methodName, objectName)}`);
1623         if (methodName in methodOverrides) {
1624           const value = methodOverrides[methodName];
1625           return typeof value === "function" ? value(...args) : value;
1626         }
1627         return iso8601[methodName](...args);
1628       };
1629     });
1630     return new Proxy(trackingMethods, {
1631       get(target, key, receiver) {
1632         const result = Reflect.get(target, key, receiver);
1633         calls.push(`get ${formatPropertyName(key, objectName)}`);
1634         return result;
1635       },
1636       has(target, key) {
1637         calls.push(`has ${formatPropertyName(key, objectName)}`);
1638         return Reflect.has(target, key);
1639       },
1640     });
1641   },
1643   /*
1644    * A custom calendar that does not allow any of its methods to be called, for
1645    * the purpose of asserting that a particular operation does not call into
1646    * user code.
1647    */
1648   calendarThrowEverything() {
1649     class CalendarThrowEverything extends Temporal.Calendar {
1650       constructor() {
1651         super("iso8601");
1652       }
1653       toString() {
1654         TemporalHelpers.assertUnreachable("toString should not be called");
1655       }
1656       dateFromFields() {
1657         TemporalHelpers.assertUnreachable("dateFromFields should not be called");
1658       }
1659       yearMonthFromFields() {
1660         TemporalHelpers.assertUnreachable("yearMonthFromFields should not be called");
1661       }
1662       monthDayFromFields() {
1663         TemporalHelpers.assertUnreachable("monthDayFromFields should not be called");
1664       }
1665       dateAdd() {
1666         TemporalHelpers.assertUnreachable("dateAdd should not be called");
1667       }
1668       dateUntil() {
1669         TemporalHelpers.assertUnreachable("dateUntil should not be called");
1670       }
1671       era() {
1672         TemporalHelpers.assertUnreachable("era should not be called");
1673       }
1674       eraYear() {
1675         TemporalHelpers.assertUnreachable("eraYear should not be called");
1676       }
1677       year() {
1678         TemporalHelpers.assertUnreachable("year should not be called");
1679       }
1680       month() {
1681         TemporalHelpers.assertUnreachable("month should not be called");
1682       }
1683       monthCode() {
1684         TemporalHelpers.assertUnreachable("monthCode should not be called");
1685       }
1686       day() {
1687         TemporalHelpers.assertUnreachable("day should not be called");
1688       }
1689       fields() {
1690         TemporalHelpers.assertUnreachable("fields should not be called");
1691       }
1692       mergeFields() {
1693         TemporalHelpers.assertUnreachable("mergeFields should not be called");
1694       }
1695     }
1697     return new CalendarThrowEverything();
1698   },
1700   /*
1701    * oneShiftTimeZone(shiftInstant, shiftNanoseconds):
1702    *
1703    * In the case of a spring-forward time zone offset transition (skipped time),
1704    * and disambiguation === 'earlier', BuiltinTimeZoneGetInstantFor subtracts a
1705    * negative number of nanoseconds from a PlainDateTime, which should balance
1706    * with the microseconds field.
1707    *
1708    * This returns an instance of a custom time zone class which skips a length
1709    * of time equal to shiftNanoseconds (a number), at the Temporal.Instant
1710    * shiftInstant. Before shiftInstant, it's identical to UTC, and after
1711    * shiftInstant it's a constant-offset time zone.
1712    *
1713    * It provides a getPossibleInstantsForCalledWith member which is an array
1714    * with the result of calling toString() on any PlainDateTimes passed to
1715    * getPossibleInstantsFor().
1716    */
1717   oneShiftTimeZone(shiftInstant, shiftNanoseconds) {
1718     class OneShiftTimeZone extends Temporal.TimeZone {
1719       constructor(shiftInstant, shiftNanoseconds) {
1720         super("+00:00");
1721         this._shiftInstant = shiftInstant;
1722         this._epoch1 = shiftInstant.epochNanoseconds;
1723         this._epoch2 = this._epoch1 + BigInt(shiftNanoseconds);
1724         this._shiftNanoseconds = shiftNanoseconds;
1725         this._shift = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, this._shiftNanoseconds);
1726         this.getPossibleInstantsForCalledWith = [];
1727       }
1729       _isBeforeShift(instant) {
1730         return instant.epochNanoseconds < this._epoch1;
1731       }
1733       getOffsetNanosecondsFor(instant) {
1734         return this._isBeforeShift(instant) ? 0 : this._shiftNanoseconds;
1735       }
1737       getPossibleInstantsFor(plainDateTime) {
1738         this.getPossibleInstantsForCalledWith.push(plainDateTime.toString({ calendarName: "never" }));
1739         const [instant] = super.getPossibleInstantsFor(plainDateTime);
1740         if (this._shiftNanoseconds > 0) {
1741           if (this._isBeforeShift(instant)) return [instant];
1742           if (instant.epochNanoseconds < this._epoch2) return [];
1743           return [instant.subtract(this._shift)];
1744         }
1745         if (instant.epochNanoseconds < this._epoch2) return [instant];
1746         const shifted = instant.subtract(this._shift);
1747         if (this._isBeforeShift(instant)) return [instant, shifted];
1748         return [shifted];
1749       }
1751       getNextTransition(instant) {
1752         return this._isBeforeShift(instant) ? this._shiftInstant : null;
1753       }
1755       getPreviousTransition(instant) {
1756         return this._isBeforeShift(instant) ? null : this._shiftInstant;
1757       }
1759       toString() {
1760         return "Custom/One_Shift";
1761       }
1762     }
1763     return new OneShiftTimeZone(shiftInstant, shiftNanoseconds);
1764   },
1766   /*
1767    * propertyBagObserver():
1768    * Returns an object that behaves like the given propertyBag but tracks Get
1769    * and Has operations on any of its properties, by appending messages to an
1770    * array. If the value of a property in propertyBag is a primitive, the value
1771    * of the returned object's property will additionally be a
1772    * TemporalHelpers.toPrimitiveObserver that will track calls to its toString
1773    * and valueOf methods in the same array. This is for the purpose of testing
1774    * order of operations that are observable from user code. objectName is used
1775    * in the log.
1776    */
1777   propertyBagObserver(calls, propertyBag, objectName) {
1778     return new Proxy(propertyBag, {
1779       ownKeys(target) {
1780         calls.push(`ownKeys ${objectName}`);
1781         return Reflect.ownKeys(target);
1782       },
1783       getOwnPropertyDescriptor(target, key) {
1784         calls.push(`getOwnPropertyDescriptor ${formatPropertyName(key, objectName)}`);
1785         return Reflect.getOwnPropertyDescriptor(target, key);
1786       },
1787       get(target, key, receiver) {
1788         calls.push(`get ${formatPropertyName(key, objectName)}`);
1789         const result = Reflect.get(target, key, receiver);
1790         if (result === undefined) {
1791           return undefined;
1792         }
1793         if ((result !== null && typeof result === "object") || typeof result === "function") {
1794           return result;
1795         }
1796         return TemporalHelpers.toPrimitiveObserver(calls, result, `${formatPropertyName(key, objectName)}`);
1797       },
1798       has(target, key) {
1799         calls.push(`has ${formatPropertyName(key, objectName)}`);
1800         return Reflect.has(target, key);
1801       },
1802     });
1803   },
1805   /*
1806    * specificOffsetTimeZone():
1807    *
1808    * This returns an instance of a custom time zone class, which returns a
1809    * specific custom value from its getOffsetNanosecondsFrom() method. This is
1810    * for the purpose of testing the validation of what this method returns.
1811    *
1812    * It also returns an empty array from getPossibleInstantsFor(), so as to
1813    * trigger calls to getOffsetNanosecondsFor() when used from the
1814    * BuiltinTimeZoneGetInstantFor operation.
1815    */
1816   specificOffsetTimeZone(offsetValue) {
1817     class SpecificOffsetTimeZone extends Temporal.TimeZone {
1818       constructor(offsetValue) {
1819         super("UTC");
1820         this._offsetValue = offsetValue;
1821       }
1823       getOffsetNanosecondsFor() {
1824         return this._offsetValue;
1825       }
1827       getPossibleInstantsFor(dt) {
1828         if (typeof this._offsetValue !== 'number' || Math.abs(this._offsetValue) >= 86400e9 || isNaN(this._offsetValue)) return [];
1829         const zdt = dt.toZonedDateTime("UTC").add({ nanoseconds: -this._offsetValue });
1830         return [zdt.toInstant()];
1831       }
1833       get id() {
1834         return this.getOffsetStringFor(new Temporal.Instant(0n));
1835       }
1836     }
1837     return new SpecificOffsetTimeZone(offsetValue);
1838   },
1840   /*
1841    * springForwardFallBackTimeZone():
1842    *
1843    * This returns an instance of a custom time zone class that implements one
1844    * single spring-forward/fall-back transition, for the purpose of testing the
1845    * disambiguation option, without depending on system time zone data.
1846    *
1847    * The spring-forward occurs at epoch second 954669600 (2000-04-02T02:00
1848    * local) and goes from offset -08:00 to -07:00.
1849    *
1850    * The fall-back occurs at epoch second 972810000 (2000-10-29T02:00 local) and
1851    * goes from offset -07:00 to -08:00.
1852    */
1853   springForwardFallBackTimeZone() {
1854     const { compare } = Temporal.PlainDateTime;
1855     const springForwardLocal = new Temporal.PlainDateTime(2000, 4, 2, 2);
1856     const springForwardEpoch = 954669600_000_000_000n;
1857     const fallBackLocal = new Temporal.PlainDateTime(2000, 10, 29, 1);
1858     const fallBackEpoch = 972810000_000_000_000n;
1859     const winterOffset = new Temporal.TimeZone('-08:00');
1860     const summerOffset = new Temporal.TimeZone('-07:00');
1862     class SpringForwardFallBackTimeZone extends Temporal.TimeZone {
1863       constructor() {
1864         super("-08:00");
1865       }
1867       getOffsetNanosecondsFor(instant) {
1868         if (instant.epochNanoseconds < springForwardEpoch ||
1869           instant.epochNanoseconds >= fallBackEpoch) {
1870           return winterOffset.getOffsetNanosecondsFor(instant);
1871         }
1872         return summerOffset.getOffsetNanosecondsFor(instant);
1873       }
1875       getPossibleInstantsFor(datetime) {
1876         if (compare(datetime, springForwardLocal) >= 0 && compare(datetime, springForwardLocal.add({ hours: 1 })) < 0) {
1877           return [];
1878         }
1879         if (compare(datetime, fallBackLocal) >= 0 && compare(datetime, fallBackLocal.add({ hours: 1 })) < 0) {
1880           return [summerOffset.getInstantFor(datetime), winterOffset.getInstantFor(datetime)];
1881         }
1882         if (compare(datetime, springForwardLocal) < 0 || compare(datetime, fallBackLocal) >= 0) {
1883           return [winterOffset.getInstantFor(datetime)];
1884         }
1885         return [summerOffset.getInstantFor(datetime)];
1886       }
1888       getPreviousTransition(instant) {
1889         if (instant.epochNanoseconds > fallBackEpoch) return new Temporal.Instant(fallBackEpoch);
1890         if (instant.epochNanoseconds > springForwardEpoch) return new Temporal.Instant(springForwardEpoch);
1891         return null;
1892       }
1894       getNextTransition(instant) {
1895         if (instant.epochNanoseconds < springForwardEpoch) return new Temporal.Instant(springForwardEpoch);
1896         if (instant.epochNanoseconds < fallBackEpoch) return new Temporal.Instant(fallBackEpoch);
1897         return null;
1898       }
1900       get id() {
1901         return "Custom/Spring_Fall";
1902       }
1904       toString() {
1905         return "Custom/Spring_Fall";
1906       }
1907     }
1908     return new SpringForwardFallBackTimeZone();
1909   },
1911   /*
1912    * timeZoneObserver:
1913    * A custom calendar that behaves exactly like the UTC time zone but tracks
1914    * calls to any of its methods, and Get/Has operations on its properties, by
1915    * appending messages to an array. This is for the purpose of testing order of
1916    * operations that are observable from user code. objectName is used in the
1917    * log. methodOverrides is an optional object containing properties with the
1918    * same name as Temporal.TimeZone methods. If the property value is a function
1919    * it will be called with the proper arguments instead of the UTC method.
1920    * Otherwise, the property value will be returned directly.
1921    */
1922   timeZoneObserver(calls, objectName, methodOverrides = {}) {
1923     const utc = new Temporal.TimeZone("UTC");
1924     const trackingMethods = {
1925       id: "UTC",
1926     };
1927     // Automatically generate the methods
1928     ["getOffsetNanosecondsFor", "getPossibleInstantsFor", "toString"].forEach((methodName) => {
1929       trackingMethods[methodName] = function (...args) {
1930         calls.push(`call ${formatPropertyName(methodName, objectName)}`);
1931         if (methodName in methodOverrides) {
1932           const value = methodOverrides[methodName];
1933           return typeof value === "function" ? value(...args) : value;
1934         }
1935         return utc[methodName](...args);
1936       };
1937     });
1938     return new Proxy(trackingMethods, {
1939       get(target, key, receiver) {
1940         const result = Reflect.get(target, key, receiver);
1941         calls.push(`get ${formatPropertyName(key, objectName)}`);
1942         return result;
1943       },
1944       has(target, key) {
1945         calls.push(`has ${formatPropertyName(key, objectName)}`);
1946         return Reflect.has(target, key);
1947       },
1948     });
1949   },
1951   /*
1952    * A custom time zone that does not allow any of its methods to be called, for
1953    * the purpose of asserting that a particular operation does not call into
1954    * user code.
1955    */
1956   timeZoneThrowEverything() {
1957     class TimeZoneThrowEverything extends Temporal.TimeZone {
1958       constructor() {
1959         super("UTC");
1960       }
1961       getOffsetNanosecondsFor() {
1962         TemporalHelpers.assertUnreachable("getOffsetNanosecondsFor should not be called");
1963       }
1964       getPossibleInstantsFor() {
1965         TemporalHelpers.assertUnreachable("getPossibleInstantsFor should not be called");
1966       }
1967       toString() {
1968         TemporalHelpers.assertUnreachable("toString should not be called");
1969       }
1970     }
1972     return new TimeZoneThrowEverything();
1973   },
1975   /*
1976    * Returns an object that will append logs of any Gets or Calls of its valueOf
1977    * or toString properties to the array calls. Both valueOf and toString will
1978    * return the actual primitiveValue. propertyName is used in the log.
1979    */
1980   toPrimitiveObserver(calls, primitiveValue, propertyName) {
1981     return {
1982       get valueOf() {
1983         calls.push(`get ${propertyName}.valueOf`);
1984         return function () {
1985           calls.push(`call ${propertyName}.valueOf`);
1986           return primitiveValue;
1987         };
1988       },
1989       get toString() {
1990         calls.push(`get ${propertyName}.toString`);
1991         return function () {
1992           calls.push(`call ${propertyName}.toString`);
1993           if (primitiveValue === undefined) return undefined;
1994           return primitiveValue.toString();
1995         };
1996       },
1997     };
1998   },
2000   /*
2001    * An object containing further methods that return arrays of ISO strings, for
2002    * testing parsers.
2003    */
2004   ISO: {
2005     /*
2006      * PlainMonthDay strings that are not valid.
2007      */
2008     plainMonthDayStringsInvalid() {
2009       return [
2010         "11-18junk",
2011         "11-18[u-ca=gregory]",
2012         "11-18[u-ca=hebrew]",
2013       ];
2014     },
2016     /*
2017      * PlainMonthDay strings that are valid and that should produce October 1st.
2018      */
2019     plainMonthDayStringsValid() {
2020       return [
2021         "10-01",
2022         "1001",
2023         "1965-10-01",
2024         "1976-10-01T152330.1+00:00",
2025         "19761001T15:23:30.1+00:00",
2026         "1976-10-01T15:23:30.1+0000",
2027         "1976-10-01T152330.1+0000",
2028         "19761001T15:23:30.1+0000",
2029         "19761001T152330.1+00:00",
2030         "19761001T152330.1+0000",
2031         "+001976-10-01T152330.1+00:00",
2032         "+0019761001T15:23:30.1+00:00",
2033         "+001976-10-01T15:23:30.1+0000",
2034         "+001976-10-01T152330.1+0000",
2035         "+0019761001T15:23:30.1+0000",
2036         "+0019761001T152330.1+00:00",
2037         "+0019761001T152330.1+0000",
2038         "1976-10-01T15:23:00",
2039         "1976-10-01T15:23",
2040         "1976-10-01T15",
2041         "1976-10-01",
2042         "--10-01",
2043         "--1001",
2044       ];
2045     },
2047     /*
2048      * PlainTime strings that may be mistaken for PlainMonthDay or
2049      * PlainYearMonth strings, and so require a time designator.
2050      */
2051     plainTimeStringsAmbiguous() {
2052       const ambiguousStrings = [
2053         "2021-12",  // ambiguity between YYYY-MM and HHMM-UU
2054         "2021-12[-12:00]",  // ditto, TZ does not disambiguate
2055         "1214",     // ambiguity between MMDD and HHMM
2056         "0229",     //   ditto, including MMDD that doesn't occur every year
2057         "1130",     //   ditto, including DD that doesn't occur in every month
2058         "12-14",    // ambiguity between MM-DD and HH-UU
2059         "12-14[-14:00]",  // ditto, TZ does not disambiguate
2060         "202112",   // ambiguity between YYYYMM and HHMMSS
2061         "202112[UTC]",  // ditto, TZ does not disambiguate
2062       ];
2063       // Adding a calendar annotation to one of these strings must not cause
2064       // disambiguation in favour of time.
2065       const stringsWithCalendar = ambiguousStrings.map((s) => s + '[u-ca=iso8601]');
2066       return ambiguousStrings.concat(stringsWithCalendar);
2067     },
2069     /*
2070      * PlainTime strings that are of similar form to PlainMonthDay and
2071      * PlainYearMonth strings, but are not ambiguous due to components that
2072      * aren't valid as months or days.
2073      */
2074     plainTimeStringsUnambiguous() {
2075       return [
2076         "2021-13",          // 13 is not a month
2077         "202113",           //   ditto
2078         "2021-13[-13:00]",  //   ditto
2079         "202113[-13:00]",   //   ditto
2080         "0000-00",          // 0 is not a month
2081         "000000",           //   ditto
2082         "0000-00[UTC]",     //   ditto
2083         "000000[UTC]",      //   ditto
2084         "1314",             // 13 is not a month
2085         "13-14",            //   ditto
2086         "1232",             // 32 is not a day
2087         "0230",             // 30 is not a day in February
2088         "0631",             // 31 is not a day in June
2089         "0000",             // 0 is neither a month nor a day
2090         "00-00",            //   ditto
2091       ];
2092     },
2094     /*
2095      * PlainYearMonth-like strings that are not valid.
2096      */
2097     plainYearMonthStringsInvalid() {
2098       return [
2099         "2020-13",
2100       ];
2101     },
2103     /*
2104      * PlainYearMonth-like strings that are valid and should produce November
2105      * 1976 in the ISO 8601 calendar.
2106      */
2107     plainYearMonthStringsValid() {
2108       return [
2109         "1976-11",
2110         "1976-11-10",
2111         "1976-11-01T09:00:00+00:00",
2112         "1976-11-01T00:00:00+05:00",
2113         "197611",
2114         "+00197611",
2115         "1976-11-18T15:23:30.1\u221202:00",
2116         "1976-11-18T152330.1+00:00",
2117         "19761118T15:23:30.1+00:00",
2118         "1976-11-18T15:23:30.1+0000",
2119         "1976-11-18T152330.1+0000",
2120         "19761118T15:23:30.1+0000",
2121         "19761118T152330.1+00:00",
2122         "19761118T152330.1+0000",
2123         "+001976-11-18T152330.1+00:00",
2124         "+0019761118T15:23:30.1+00:00",
2125         "+001976-11-18T15:23:30.1+0000",
2126         "+001976-11-18T152330.1+0000",
2127         "+0019761118T15:23:30.1+0000",
2128         "+0019761118T152330.1+00:00",
2129         "+0019761118T152330.1+0000",
2130         "1976-11-18T15:23",
2131         "1976-11-18T15",
2132         "1976-11-18",
2133       ];
2134     },
2136     /*
2137      * PlainYearMonth-like strings that are valid and should produce November of
2138      * the ISO year -9999.
2139      */
2140     plainYearMonthStringsValidNegativeYear() {
2141       return [
2142         "\u2212009999-11",
2143       ];
2144     },
2145   }