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