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