shell.js (51278B)
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, assert.throwsAsync] 9 ---*/ 10 11 /** 12 * Defines the **sole** asynchronous test of a file. 13 * @see {@link ../docs/rfcs/async-helpers.md} for background. 14 * 15 * @param {Function} testFunc a callback whose returned promise indicates test results 16 * (fulfillment for success, rejection for failure) 17 * @returns {void} 18 */ 19 function asyncTest(testFunc) { 20 if (!Object.prototype.hasOwnProperty.call(globalThis, "$DONE")) { 21 throw new Test262Error("asyncTest called without async flag"); 22 } 23 if (typeof testFunc !== "function") { 24 $DONE(new Test262Error("asyncTest called with non-function argument")); 25 return; 26 } 27 try { 28 testFunc().then( 29 function () { 30 $DONE(); 31 }, 32 function (error) { 33 $DONE(error); 34 } 35 ); 36 } catch (syncError) { 37 $DONE(syncError); 38 } 39 } 40 41 /** 42 * Asserts that a callback asynchronously throws an instance of a particular 43 * error (i.e., returns a promise whose rejection value is an object referencing 44 * the constructor). 45 * 46 * @param {Function} expectedErrorConstructor the expected constructor of the 47 * rejection value 48 * @param {Function} func the callback 49 * @param {string} [message] the prefix to use for failure messages 50 * @returns {Promise<void>} fulfills if the expected error is thrown, 51 * otherwise rejects 52 */ 53 assert.throwsAsync = function (expectedErrorConstructor, func, message) { 54 return new Promise(function (resolve) { 55 var fail = function (detail) { 56 if (message === undefined) { 57 throw new Test262Error(detail); 58 } 59 throw new Test262Error(message + " " + detail); 60 }; 61 if (typeof expectedErrorConstructor !== "function") { 62 fail("assert.throwsAsync called with an argument that is not an error constructor"); 63 } 64 if (typeof func !== "function") { 65 fail("assert.throwsAsync called with an argument that is not a function"); 66 } 67 var expectedName = expectedErrorConstructor.name; 68 var expectation = "Expected a " + expectedName + " to be thrown asynchronously"; 69 var res; 70 try { 71 res = func(); 72 } catch (thrown) { 73 fail(expectation + " but the function threw synchronously"); 74 } 75 if (res === null || typeof res !== "object" || typeof res.then !== "function") { 76 fail(expectation + " but result was not a thenable"); 77 } 78 var onResFulfilled, onResRejected; 79 var resSettlementP = new Promise(function (onFulfilled, onRejected) { 80 onResFulfilled = onFulfilled; 81 onResRejected = onRejected; 82 }); 83 try { 84 res.then(onResFulfilled, onResRejected) 85 } catch (thrown) { 86 fail(expectation + " but .then threw synchronously"); 87 } 88 resolve(resSettlementP.then( 89 function () { 90 fail(expectation + " but no exception was thrown at all"); 91 }, 92 function (thrown) { 93 var actualName; 94 if (thrown === null || typeof thrown !== "object") { 95 fail(expectation + " but thrown value was not an object"); 96 } else if (thrown.constructor !== expectedErrorConstructor) { 97 actualName = thrown.constructor.name; 98 if (expectedName === actualName) { 99 fail(expectation + 100 " but got a different error constructor with the same name"); 101 } 102 fail(expectation + " but got a " + actualName); 103 } 104 } 105 )); 106 }); 107 }; 108 109 // file: temporalHelpers.js 110 // Copyright (C) 2021 Igalia, S.L. All rights reserved. 111 // This code is governed by the BSD license found in the LICENSE file. 112 /*--- 113 description: | 114 This defines helper objects and functions for testing Temporal. 115 defines: [TemporalHelpers] 116 features: [Symbol.species, Symbol.iterator, Temporal] 117 ---*/ 118 119 const ASCII_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/u; 120 121 function formatPropertyName(propertyKey, objectName = "") { 122 switch (typeof propertyKey) { 123 case "symbol": 124 if (Symbol.keyFor(propertyKey) !== undefined) { 125 return `${objectName}[Symbol.for('${Symbol.keyFor(propertyKey)}')]`; 126 } else if (propertyKey.description.startsWith("Symbol.")) { 127 return `${objectName}[${propertyKey.description}]`; 128 } else { 129 return `${objectName}[Symbol('${propertyKey.description}')]`; 130 } 131 case "string": 132 if (propertyKey !== String(Number(propertyKey))) { 133 if (ASCII_IDENTIFIER.test(propertyKey)) { 134 return objectName ? `${objectName}.${propertyKey}` : propertyKey; 135 } 136 return `${objectName}['${propertyKey.replace(/'/g, "\\'")}']`; 137 } 138 // fall through 139 default: 140 // integer or string integer-index 141 return `${objectName}[${propertyKey}]`; 142 } 143 } 144 145 const SKIP_SYMBOL = Symbol("Skip"); 146 147 var TemporalHelpers = { 148 /* 149 * Codes and maximum lengths of months in the ISO 8601 calendar. 150 */ 151 ISOMonths: [ 152 { month: 1, monthCode: "M01", daysInMonth: 31 }, 153 { month: 2, monthCode: "M02", daysInMonth: 29 }, 154 { month: 3, monthCode: "M03", daysInMonth: 31 }, 155 { month: 4, monthCode: "M04", daysInMonth: 30 }, 156 { month: 5, monthCode: "M05", daysInMonth: 31 }, 157 { month: 6, monthCode: "M06", daysInMonth: 30 }, 158 { month: 7, monthCode: "M07", daysInMonth: 31 }, 159 { month: 8, monthCode: "M08", daysInMonth: 31 }, 160 { month: 9, monthCode: "M09", daysInMonth: 30 }, 161 { month: 10, monthCode: "M10", daysInMonth: 31 }, 162 { month: 11, monthCode: "M11", daysInMonth: 30 }, 163 { month: 12, monthCode: "M12", daysInMonth: 31 } 164 ], 165 166 /* 167 * List of known calendar eras and their possible aliases. 168 * 169 * https://tc39.es/proposal-intl-era-monthcode/#table-eras 170 */ 171 CalendarEras: { 172 buddhist: [ 173 { era: "be" }, 174 ], 175 coptic: [ 176 { era: "am" }, 177 ], 178 ethiopic: [ 179 { era: "aa", aliases: ["mundi"] }, 180 { era: "am", aliases: ["incar"] }, 181 ], 182 ethioaa: [ 183 { era: "aa", aliases: ["mundi"] }, 184 ], 185 gregory: [ 186 { era: "bce", aliases: ["bc"] }, 187 { era: "ce", aliases: ["ad"] }, 188 ], 189 hebrew: [ 190 { era: "am" }, 191 ], 192 indian: [ 193 { era: "shaka" }, 194 ], 195 islamic: [ 196 { era: "ah" }, 197 { era: "bh" }, 198 ], 199 "islamic-civil": [ 200 { era: "bh" }, 201 { era: "ah" }, 202 ], 203 "islamic-rgsa": [ 204 { era: "bh" }, 205 { era: "ah" }, 206 ], 207 "islamic-tbla": [ 208 { era: "bh" }, 209 { era: "ah" }, 210 ], 211 "islamic-umalqura": [ 212 { era: "bh" }, 213 { era: "ah" }, 214 ], 215 japanese: [ 216 { era: "bce", aliases: ["bc"] }, 217 { era: "ce", aliases: ["ad"] }, 218 { era: "heisei" }, 219 { era: "meiji" }, 220 { era: "reiwa" }, 221 { era: "showa" }, 222 { era: "taisho" }, 223 ], 224 persian: [ 225 { era: "ap" }, 226 ], 227 roc: [ 228 { era: "roc", aliases: ["minguo"] }, 229 { era: "broc", aliases: ["before-roc", "minguo-qian"] }, 230 ], 231 }, 232 233 /* 234 * Return the canonical era code. 235 */ 236 canonicalizeCalendarEra(calendarId, eraName) { 237 assert.sameValue(typeof calendarId, "string", "calendar must be string in canonicalizeCalendarEra"); 238 239 if (!Object.prototype.hasOwnProperty.call(TemporalHelpers.CalendarEras, calendarId)) { 240 assert.sameValue(eraName, undefined); 241 return undefined; 242 } 243 244 assert.sameValue(typeof eraName, "string", "eraName must be string or undefined in canonicalizeCalendarEra"); 245 246 for (let {era, aliases = []} of TemporalHelpers.CalendarEras[calendarId]) { 247 if (era === eraName || aliases.includes(eraName)) { 248 return era; 249 } 250 } 251 throw new Test262Error(`Unsupported era name: ${eraName}`); 252 }, 253 254 /* 255 * assertDuration(duration, years, ..., nanoseconds[, description]): 256 * 257 * Shorthand for asserting that each field of a Temporal.Duration is equal to 258 * an expected value. 259 */ 260 assertDuration(duration, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, description = "") { 261 const prefix = description ? `${description}: ` : ""; 262 assert(duration instanceof Temporal.Duration, `${prefix}instanceof`); 263 assert.sameValue(duration.years, years, `${prefix}years result:`); 264 assert.sameValue(duration.months, months, `${prefix}months result:`); 265 assert.sameValue(duration.weeks, weeks, `${prefix}weeks result:`); 266 assert.sameValue(duration.days, days, `${prefix}days result:`); 267 assert.sameValue(duration.hours, hours, `${prefix}hours result:`); 268 assert.sameValue(duration.minutes, minutes, `${prefix}minutes result:`); 269 assert.sameValue(duration.seconds, seconds, `${prefix}seconds result:`); 270 assert.sameValue(duration.milliseconds, milliseconds, `${prefix}milliseconds result:`); 271 assert.sameValue(duration.microseconds, microseconds, `${prefix}microseconds result:`); 272 assert.sameValue(duration.nanoseconds, nanoseconds, `${prefix}nanoseconds result`); 273 }, 274 275 /* 276 * assertDateDuration(duration, years, months, weeks, days, [, description]): 277 * 278 * Shorthand for asserting that each date field of a Temporal.Duration is 279 * equal to an expected value. 280 */ 281 assertDateDuration(duration, years, months, weeks, days, description = "") { 282 const prefix = description ? `${description}: ` : ""; 283 assert(duration instanceof Temporal.Duration, `${prefix}instanceof`); 284 assert.sameValue(duration.years, years, `${prefix}years result:`); 285 assert.sameValue(duration.months, months, `${prefix}months result:`); 286 assert.sameValue(duration.weeks, weeks, `${prefix}weeks result:`); 287 assert.sameValue(duration.days, days, `${prefix}days result:`); 288 assert.sameValue(duration.hours, 0, `${prefix}hours result should be zero:`); 289 assert.sameValue(duration.minutes, 0, `${prefix}minutes result should be zero:`); 290 assert.sameValue(duration.seconds, 0, `${prefix}seconds result should be zero:`); 291 assert.sameValue(duration.milliseconds, 0, `${prefix}milliseconds result should be zero:`); 292 assert.sameValue(duration.microseconds, 0, `${prefix}microseconds result should be zero:`); 293 assert.sameValue(duration.nanoseconds, 0, `${prefix}nanoseconds result should be zero:`); 294 }, 295 296 /* 297 * assertDurationsEqual(actual, expected[, description]): 298 * 299 * Shorthand for asserting that each field of a Temporal.Duration is equal to 300 * the corresponding field in another Temporal.Duration. 301 */ 302 assertDurationsEqual(actual, expected, description = "") { 303 const prefix = description ? `${description}: ` : ""; 304 assert(expected instanceof Temporal.Duration, `${prefix}expected value should be a Temporal.Duration`); 305 TemporalHelpers.assertDuration(actual, expected.years, expected.months, expected.weeks, expected.days, expected.hours, expected.minutes, expected.seconds, expected.milliseconds, expected.microseconds, expected.nanoseconds, description); 306 }, 307 308 /* 309 * assertInstantsEqual(actual, expected[, description]): 310 * 311 * Shorthand for asserting that two Temporal.Instants are of the correct type 312 * and equal according to their equals() methods. 313 */ 314 assertInstantsEqual(actual, expected, description = "") { 315 const prefix = description ? `${description}: ` : ""; 316 assert(expected instanceof Temporal.Instant, `${prefix}expected value should be a Temporal.Instant`); 317 assert(actual instanceof Temporal.Instant, `${prefix}instanceof`); 318 assert(actual.equals(expected), `${prefix}equals method`); 319 }, 320 321 /* 322 * assertPlainDate(date, year, ..., nanosecond[, description[, era, eraYear]]): 323 * 324 * Shorthand for asserting that each field of a Temporal.PlainDate is equal to 325 * an expected value. (Except the `calendar` property, since callers may want 326 * to assert either object equality with an object they put in there, or the 327 * value of date.calendarId.) 328 */ 329 assertPlainDate(date, year, month, monthCode, day, description = "", era = undefined, eraYear = undefined) { 330 const prefix = description ? `${description}: ` : ""; 331 assert(date instanceof Temporal.PlainDate, `${prefix}instanceof`); 332 assert.sameValue( 333 TemporalHelpers.canonicalizeCalendarEra(date.calendarId, date.era), 334 TemporalHelpers.canonicalizeCalendarEra(date.calendarId, era), 335 `${prefix}era result:` 336 ); 337 assert.sameValue(date.eraYear, eraYear, `${prefix}eraYear result:`); 338 assert.sameValue(date.year, year, `${prefix}year result:`); 339 assert.sameValue(date.month, month, `${prefix}month result:`); 340 assert.sameValue(date.monthCode, monthCode, `${prefix}monthCode result:`); 341 assert.sameValue(date.day, day, `${prefix}day result:`); 342 }, 343 344 /* 345 * assertPlainDateTime(datetime, year, ..., nanosecond[, description[, era, eraYear]]): 346 * 347 * Shorthand for asserting that each field of a Temporal.PlainDateTime is 348 * equal to an expected value. (Except the `calendar` property, since callers 349 * may want to assert either object equality with an object they put in there, 350 * or the value of datetime.calendarId.) 351 */ 352 assertPlainDateTime(datetime, year, month, monthCode, day, hour, minute, second, millisecond, microsecond, nanosecond, description = "", era = undefined, eraYear = undefined) { 353 const prefix = description ? `${description}: ` : ""; 354 assert(datetime instanceof Temporal.PlainDateTime, `${prefix}instanceof`); 355 assert.sameValue( 356 TemporalHelpers.canonicalizeCalendarEra(datetime.calendarId, datetime.era), 357 TemporalHelpers.canonicalizeCalendarEra(datetime.calendarId, era), 358 `${prefix}era result:` 359 ); 360 assert.sameValue(datetime.eraYear, eraYear, `${prefix}eraYear result:`); 361 assert.sameValue(datetime.year, year, `${prefix}year result:`); 362 assert.sameValue(datetime.month, month, `${prefix}month result:`); 363 assert.sameValue(datetime.monthCode, monthCode, `${prefix}monthCode result:`); 364 assert.sameValue(datetime.day, day, `${prefix}day result:`); 365 assert.sameValue(datetime.hour, hour, `${prefix}hour result:`); 366 assert.sameValue(datetime.minute, minute, `${prefix}minute result:`); 367 assert.sameValue(datetime.second, second, `${prefix}second result:`); 368 assert.sameValue(datetime.millisecond, millisecond, `${prefix}millisecond result:`); 369 assert.sameValue(datetime.microsecond, microsecond, `${prefix}microsecond result:`); 370 assert.sameValue(datetime.nanosecond, nanosecond, `${prefix}nanosecond result:`); 371 }, 372 373 /* 374 * assertPlainDateTimesEqual(actual, expected[, description]): 375 * 376 * Shorthand for asserting that two Temporal.PlainDateTimes are of the correct 377 * type, equal according to their equals() methods, and additionally that 378 * their calendar internal slots are the same value. 379 */ 380 assertPlainDateTimesEqual(actual, expected, description = "") { 381 const prefix = description ? `${description}: ` : ""; 382 assert(expected instanceof Temporal.PlainDateTime, `${prefix}expected value should be a Temporal.PlainDateTime`); 383 assert(actual instanceof Temporal.PlainDateTime, `${prefix}instanceof`); 384 assert(actual.equals(expected), `${prefix}equals method`); 385 assert.sameValue( 386 actual.calendarId, 387 expected.calendarId, 388 `${prefix}calendar same value:` 389 ); 390 }, 391 392 /* 393 * assertPlainMonthDay(monthDay, monthCode, day[, description [, referenceISOYear]]): 394 * 395 * Shorthand for asserting that each field of a Temporal.PlainMonthDay is 396 * equal to an expected value. (Except the `calendar` property, since callers 397 * may want to assert either object equality with an object they put in there, 398 * or the value of monthDay.calendarId().) 399 */ 400 assertPlainMonthDay(monthDay, monthCode, day, description = "", referenceISOYear = 1972) { 401 const prefix = description ? `${description}: ` : ""; 402 assert(monthDay instanceof Temporal.PlainMonthDay, `${prefix}instanceof`); 403 assert.sameValue(monthDay.monthCode, monthCode, `${prefix}monthCode result:`); 404 assert.sameValue(monthDay.day, day, `${prefix}day result:`); 405 const isoYear = Number(monthDay.toString({ calendarName: "always" }).split("-")[0]); 406 assert.sameValue(isoYear, referenceISOYear, `${prefix}referenceISOYear result:`); 407 }, 408 409 /* 410 * assertPlainTime(time, hour, ..., nanosecond[, description]): 411 * 412 * Shorthand for asserting that each field of a Temporal.PlainTime is equal to 413 * an expected value. 414 */ 415 assertPlainTime(time, hour, minute, second, millisecond, microsecond, nanosecond, description = "") { 416 const prefix = description ? `${description}: ` : ""; 417 assert(time instanceof Temporal.PlainTime, `${prefix}instanceof`); 418 assert.sameValue(time.hour, hour, `${prefix}hour result:`); 419 assert.sameValue(time.minute, minute, `${prefix}minute result:`); 420 assert.sameValue(time.second, second, `${prefix}second result:`); 421 assert.sameValue(time.millisecond, millisecond, `${prefix}millisecond result:`); 422 assert.sameValue(time.microsecond, microsecond, `${prefix}microsecond result:`); 423 assert.sameValue(time.nanosecond, nanosecond, `${prefix}nanosecond result:`); 424 }, 425 426 /* 427 * assertPlainTimesEqual(actual, expected[, description]): 428 * 429 * Shorthand for asserting that two Temporal.PlainTimes are of the correct 430 * type and equal according to their equals() methods. 431 */ 432 assertPlainTimesEqual(actual, expected, description = "") { 433 const prefix = description ? `${description}: ` : ""; 434 assert(expected instanceof Temporal.PlainTime, `${prefix}expected value should be a Temporal.PlainTime`); 435 assert(actual instanceof Temporal.PlainTime, `${prefix}instanceof`); 436 assert(actual.equals(expected), `${prefix}equals method`); 437 }, 438 439 /* 440 * assertPlainYearMonth(yearMonth, year, month, monthCode[, description[, era, eraYear, referenceISODay]]): 441 * 442 * Shorthand for asserting that each field of a Temporal.PlainYearMonth is 443 * equal to an expected value. (Except the `calendar` property, since callers 444 * may want to assert either object equality with an object they put in there, 445 * or the value of yearMonth.calendarId.) 446 * 447 * Pass null as the referenceISODay if you don't want to give it explicitly. 448 * In that case, the expected referenceISODay will be computed using PlainDate 449 * and only verified for consistency, not for equality with a specific value. 450 */ 451 assertPlainYearMonth(yearMonth, year, month, monthCode, description = "", era = undefined, eraYear = undefined, referenceISODay = 1) { 452 const prefix = description ? `${description}: ` : ""; 453 assert(typeof referenceISODay === "number" || referenceISODay === null, 454 `TemporalHelpers.assertPlainYearMonth() referenceISODay argument should be a number or null, not ${referenceISODay}`); 455 assert(yearMonth instanceof Temporal.PlainYearMonth, `${prefix}instanceof`); 456 assert.sameValue( 457 TemporalHelpers.canonicalizeCalendarEra(yearMonth.calendarId, yearMonth.era), 458 TemporalHelpers.canonicalizeCalendarEra(yearMonth.calendarId, era), 459 `${prefix}era result:` 460 ); 461 assert.sameValue(yearMonth.eraYear, eraYear, `${prefix}eraYear result:`); 462 assert.sameValue(yearMonth.year, year, `${prefix}year result:`); 463 assert.sameValue(yearMonth.month, month, `${prefix}month result:`); 464 assert.sameValue(yearMonth.monthCode, monthCode, `${prefix}monthCode result:`); 465 const isoDay = Number(yearMonth.toString({ calendarName: "always" }).slice(1).split("-")[2].slice(0, 2)); 466 const expectedISODay = referenceISODay ?? yearMonth.toPlainDate({ day: 1 }).withCalendar("iso8601").day; 467 assert.sameValue(isoDay, expectedISODay, `${prefix}referenceISODay result:`); 468 }, 469 470 /* 471 * assertZonedDateTimesEqual(actual, expected[, description]): 472 * 473 * Shorthand for asserting that two Temporal.ZonedDateTimes are of the correct 474 * type, equal according to their equals() methods, and additionally that 475 * their time zones and calendar internal slots are the same value. 476 */ 477 assertZonedDateTimesEqual(actual, expected, description = "") { 478 const prefix = description ? `${description}: ` : ""; 479 assert(expected instanceof Temporal.ZonedDateTime, `${prefix}expected value should be a Temporal.ZonedDateTime`); 480 assert(actual instanceof Temporal.ZonedDateTime, `${prefix}instanceof`); 481 assert(actual.equals(expected), `${prefix}equals method`); 482 assert.sameValue(actual.timeZoneId, expected.timeZoneId, `${prefix}time zone same value:`); 483 assert.sameValue( 484 actual.calendarId, 485 expected.calendarId, 486 `${prefix}calendar same value:` 487 ); 488 }, 489 490 /* 491 * assertUnreachable(description): 492 * 493 * Helper for asserting that code is not executed. 494 */ 495 assertUnreachable(description) { 496 let message = "This code should not be executed"; 497 if (description) { 498 message = `${message}: ${description}`; 499 } 500 throw new Test262Error(message); 501 }, 502 503 /* 504 * checkPlainDateTimeConversionFastPath(func): 505 * 506 * ToTemporalDate and ToTemporalTime should both, if given a 507 * Temporal.PlainDateTime instance, convert to the desired type by reading the 508 * PlainDateTime's internal slots, rather than calling any getters. 509 * 510 * func(datetime) is the actual operation to test, that must 511 * internally call the abstract operation ToTemporalDate or ToTemporalTime. 512 * It is passed a Temporal.PlainDateTime instance. 513 */ 514 checkPlainDateTimeConversionFastPath(func, message = "checkPlainDateTimeConversionFastPath") { 515 const actual = []; 516 const expected = []; 517 518 const calendar = "iso8601"; 519 const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar); 520 const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.PlainDateTime.prototype); 521 ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].forEach((property) => { 522 Object.defineProperty(datetime, property, { 523 get() { 524 actual.push(`get ${formatPropertyName(property)}`); 525 const value = prototypeDescrs[property].get.call(this); 526 return { 527 toString() { 528 actual.push(`toString ${formatPropertyName(property)}`); 529 return value.toString(); 530 }, 531 valueOf() { 532 actual.push(`valueOf ${formatPropertyName(property)}`); 533 return value; 534 }, 535 }; 536 }, 537 }); 538 }); 539 Object.defineProperty(datetime, "calendar", { 540 get() { 541 actual.push("get calendar"); 542 return calendar; 543 }, 544 }); 545 546 func(datetime); 547 assert.compareArray(actual, expected, `${message}: property getters not called`); 548 }, 549 550 /* 551 * Check that an options bag that accepts units written in the singular form, 552 * also accepts the same units written in the plural form. 553 * func(unit) should call the method with the appropriate options bag 554 * containing unit as a value. This will be called twice for each element of 555 * validSingularUnits, once with singular and once with plural, and the 556 * results of each pair should be the same (whether a Temporal object or a 557 * primitive value.) 558 */ 559 checkPluralUnitsAccepted(func, validSingularUnits) { 560 const plurals = { 561 year: "years", 562 month: "months", 563 week: "weeks", 564 day: "days", 565 hour: "hours", 566 minute: "minutes", 567 second: "seconds", 568 millisecond: "milliseconds", 569 microsecond: "microseconds", 570 nanosecond: "nanoseconds", 571 }; 572 573 validSingularUnits.forEach((unit) => { 574 const singularValue = func(unit); 575 const pluralValue = func(plurals[unit]); 576 const desc = `Plural ${plurals[unit]} produces the same result as singular ${unit}`; 577 if (singularValue instanceof Temporal.Duration) { 578 TemporalHelpers.assertDurationsEqual(pluralValue, singularValue, desc); 579 } else if (singularValue instanceof Temporal.Instant) { 580 TemporalHelpers.assertInstantsEqual(pluralValue, singularValue, desc); 581 } else if (singularValue instanceof Temporal.PlainDateTime) { 582 TemporalHelpers.assertPlainDateTimesEqual(pluralValue, singularValue, desc); 583 } else if (singularValue instanceof Temporal.PlainTime) { 584 TemporalHelpers.assertPlainTimesEqual(pluralValue, singularValue, desc); 585 } else if (singularValue instanceof Temporal.ZonedDateTime) { 586 TemporalHelpers.assertZonedDateTimesEqual(pluralValue, singularValue, desc); 587 } else { 588 assert.sameValue(pluralValue, singularValue); 589 } 590 }); 591 }, 592 593 /* 594 * checkRoundingIncrementOptionWrongType(checkFunc, assertTrueResultFunc, assertObjectResultFunc): 595 * 596 * Checks the type handling of the roundingIncrement option. 597 * checkFunc(roundingIncrement) is a function which takes the value of 598 * roundingIncrement to test, and calls the method under test with it, 599 * returning the result. assertTrueResultFunc(result, description) should 600 * assert that result is the expected result with roundingIncrement: true, and 601 * assertObjectResultFunc(result, description) should assert that result is 602 * the expected result with roundingIncrement being an object with a valueOf() 603 * method. 604 */ 605 checkRoundingIncrementOptionWrongType(checkFunc, assertTrueResultFunc, assertObjectResultFunc) { 606 // null converts to 0, which is out of range 607 assert.throws(RangeError, () => checkFunc(null), "null"); 608 // Booleans convert to either 0 or 1, and 1 is allowed 609 const trueResult = checkFunc(true); 610 assertTrueResultFunc(trueResult, "true"); 611 assert.throws(RangeError, () => checkFunc(false), "false"); 612 // Symbols and BigInts cannot convert to numbers 613 assert.throws(TypeError, () => checkFunc(Symbol()), "symbol"); 614 assert.throws(TypeError, () => checkFunc(2n), "bigint"); 615 616 // Objects prefer their valueOf() methods when converting to a number 617 assert.throws(RangeError, () => checkFunc({}), "plain object"); 618 619 const expected = [ 620 "get roundingIncrement.valueOf", 621 "call roundingIncrement.valueOf", 622 ]; 623 const actual = []; 624 const observer = TemporalHelpers.toPrimitiveObserver(actual, 2, "roundingIncrement"); 625 const objectResult = checkFunc(observer); 626 assertObjectResultFunc(objectResult, "object with valueOf"); 627 assert.compareArray(actual, expected, "order of operations"); 628 }, 629 630 /* 631 * checkStringOptionWrongType(propertyName, value, checkFunc, assertFunc): 632 * 633 * Checks the type handling of a string option, of which there are several in 634 * Temporal. 635 * propertyName is the name of the option, and value is the value that 636 * assertFunc should expect it to have. 637 * checkFunc(value) is a function which takes the value of the option to test, 638 * and calls the method under test with it, returning the result. 639 * assertFunc(result, description) should assert that result is the expected 640 * result with the option value being an object with a toString() method 641 * which returns the given value. 642 */ 643 checkStringOptionWrongType(propertyName, value, checkFunc, assertFunc) { 644 // null converts to the string "null", which is an invalid string value 645 assert.throws(RangeError, () => checkFunc(null), "null"); 646 // Booleans convert to the strings "true" or "false", which are invalid 647 assert.throws(RangeError, () => checkFunc(true), "true"); 648 assert.throws(RangeError, () => checkFunc(false), "false"); 649 // Symbols cannot convert to strings 650 assert.throws(TypeError, () => checkFunc(Symbol()), "symbol"); 651 // Numbers convert to strings which are invalid 652 assert.throws(RangeError, () => checkFunc(2), "number"); 653 // BigInts convert to strings which are invalid 654 assert.throws(RangeError, () => checkFunc(2n), "bigint"); 655 656 // Objects prefer their toString() methods when converting to a string 657 assert.throws(RangeError, () => checkFunc({}), "plain object"); 658 659 const expected = [ 660 `get ${propertyName}.toString`, 661 `call ${propertyName}.toString`, 662 ]; 663 const actual = []; 664 const observer = TemporalHelpers.toPrimitiveObserver(actual, value, propertyName); 665 const result = checkFunc(observer); 666 assertFunc(result, "object with toString"); 667 assert.compareArray(actual, expected, "order of operations"); 668 }, 669 670 /* 671 * checkSubclassingIgnored(construct, constructArgs, method, methodArgs, 672 * resultAssertions): 673 * 674 * Methods of Temporal classes that return a new instance of the same class, 675 * must not take the constructor of a subclass into account, nor the @@species 676 * property. This helper runs tests to ensure this. 677 * 678 * construct(...constructArgs) must yield a valid instance of the Temporal 679 * class. instance[method](...methodArgs) is the method call under test, which 680 * must also yield a valid instance of the same Temporal class, not a 681 * subclass. See below for the individual tests that this runs. 682 * resultAssertions() is a function that performs additional assertions on the 683 * instance returned by the method under test. 684 */ 685 checkSubclassingIgnored(...args) { 686 this.checkSubclassConstructorNotObject(...args); 687 this.checkSubclassConstructorUndefined(...args); 688 this.checkSubclassConstructorThrows(...args); 689 this.checkSubclassConstructorNotCalled(...args); 690 this.checkSubclassSpeciesInvalidResult(...args); 691 this.checkSubclassSpeciesNotAConstructor(...args); 692 this.checkSubclassSpeciesNull(...args); 693 this.checkSubclassSpeciesUndefined(...args); 694 this.checkSubclassSpeciesThrows(...args); 695 }, 696 697 /* 698 * Checks that replacing the 'constructor' property of the instance with 699 * various primitive values does not affect the returned new instance. 700 */ 701 checkSubclassConstructorNotObject(construct, constructArgs, method, methodArgs, resultAssertions) { 702 function check(value, description) { 703 const instance = new construct(...constructArgs); 704 instance.constructor = value; 705 const result = instance[method](...methodArgs); 706 assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description); 707 resultAssertions(result); 708 } 709 710 check(null, "null"); 711 check(true, "true"); 712 check("test", "string"); 713 check(Symbol(), "Symbol"); 714 check(7, "number"); 715 check(7n, "bigint"); 716 }, 717 718 /* 719 * Checks that replacing the 'constructor' property of the subclass with 720 * undefined does not affect the returned new instance. 721 */ 722 checkSubclassConstructorUndefined(construct, constructArgs, method, methodArgs, resultAssertions) { 723 let called = 0; 724 725 class MySubclass extends construct { 726 constructor() { 727 ++called; 728 super(...constructArgs); 729 } 730 } 731 732 const instance = new MySubclass(); 733 assert.sameValue(called, 1); 734 735 MySubclass.prototype.constructor = undefined; 736 737 const result = instance[method](...methodArgs); 738 assert.sameValue(called, 1); 739 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 740 resultAssertions(result); 741 }, 742 743 /* 744 * Checks that making the 'constructor' property of the instance throw when 745 * called does not affect the returned new instance. 746 */ 747 checkSubclassConstructorThrows(construct, constructArgs, method, methodArgs, resultAssertions) { 748 function CustomError() {} 749 const instance = new construct(...constructArgs); 750 Object.defineProperty(instance, "constructor", { 751 get() { 752 throw new CustomError(); 753 } 754 }); 755 const result = instance[method](...methodArgs); 756 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 757 resultAssertions(result); 758 }, 759 760 /* 761 * Checks that when subclassing, the subclass constructor is not called by 762 * the method under test. 763 */ 764 checkSubclassConstructorNotCalled(construct, constructArgs, method, methodArgs, resultAssertions) { 765 let called = 0; 766 767 class MySubclass extends construct { 768 constructor() { 769 ++called; 770 super(...constructArgs); 771 } 772 } 773 774 const instance = new MySubclass(); 775 assert.sameValue(called, 1); 776 777 const result = instance[method](...methodArgs); 778 assert.sameValue(called, 1); 779 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 780 resultAssertions(result); 781 }, 782 783 /* 784 * Check that the constructor's @@species property is ignored when it's a 785 * constructor that returns a non-object value. 786 */ 787 checkSubclassSpeciesInvalidResult(construct, constructArgs, method, methodArgs, resultAssertions) { 788 function check(value, description) { 789 const instance = new construct(...constructArgs); 790 instance.constructor = { 791 [Symbol.species]: function() { 792 return value; 793 }, 794 }; 795 const result = instance[method](...methodArgs); 796 assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description); 797 resultAssertions(result); 798 } 799 800 check(undefined, "undefined"); 801 check(null, "null"); 802 check(true, "true"); 803 check("test", "string"); 804 check(Symbol(), "Symbol"); 805 check(7, "number"); 806 check(7n, "bigint"); 807 check({}, "plain object"); 808 }, 809 810 /* 811 * Check that the constructor's @@species property is ignored when it's not a 812 * constructor. 813 */ 814 checkSubclassSpeciesNotAConstructor(construct, constructArgs, method, methodArgs, resultAssertions) { 815 function check(value, description) { 816 const instance = new construct(...constructArgs); 817 instance.constructor = { 818 [Symbol.species]: value, 819 }; 820 const result = instance[method](...methodArgs); 821 assert.sameValue(Object.getPrototypeOf(result), construct.prototype, description); 822 resultAssertions(result); 823 } 824 825 check(true, "true"); 826 check("test", "string"); 827 check(Symbol(), "Symbol"); 828 check(7, "number"); 829 check(7n, "bigint"); 830 check({}, "plain object"); 831 }, 832 833 /* 834 * Check that the constructor's @@species property is ignored when it's null. 835 */ 836 checkSubclassSpeciesNull(construct, constructArgs, method, methodArgs, resultAssertions) { 837 let called = 0; 838 839 class MySubclass extends construct { 840 constructor() { 841 ++called; 842 super(...constructArgs); 843 } 844 } 845 846 const instance = new MySubclass(); 847 assert.sameValue(called, 1); 848 849 MySubclass.prototype.constructor = { 850 [Symbol.species]: null, 851 }; 852 853 const result = instance[method](...methodArgs); 854 assert.sameValue(called, 1); 855 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 856 resultAssertions(result); 857 }, 858 859 /* 860 * Check that the constructor's @@species property is ignored when it's 861 * undefined. 862 */ 863 checkSubclassSpeciesUndefined(construct, constructArgs, method, methodArgs, resultAssertions) { 864 let called = 0; 865 866 class MySubclass extends construct { 867 constructor() { 868 ++called; 869 super(...constructArgs); 870 } 871 } 872 873 const instance = new MySubclass(); 874 assert.sameValue(called, 1); 875 876 MySubclass.prototype.constructor = { 877 [Symbol.species]: undefined, 878 }; 879 880 const result = instance[method](...methodArgs); 881 assert.sameValue(called, 1); 882 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 883 resultAssertions(result); 884 }, 885 886 /* 887 * Check that the constructor's @@species property is ignored when it throws, 888 * i.e. it is not called at all. 889 */ 890 checkSubclassSpeciesThrows(construct, constructArgs, method, methodArgs, resultAssertions) { 891 function CustomError() {} 892 893 const instance = new construct(...constructArgs); 894 instance.constructor = { 895 get [Symbol.species]() { 896 throw new CustomError(); 897 }, 898 }; 899 900 const result = instance[method](...methodArgs); 901 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 902 }, 903 904 /* 905 * checkSubclassingIgnoredStatic(construct, method, methodArgs, resultAssertions): 906 * 907 * Static methods of Temporal classes that return a new instance of the class, 908 * must not use the this-value as a constructor. This helper runs tests to 909 * ensure this. 910 * 911 * construct[method](...methodArgs) is the static method call under test, and 912 * must yield a valid instance of the Temporal class, not a subclass. See 913 * below for the individual tests that this runs. 914 * resultAssertions() is a function that performs additional assertions on the 915 * instance returned by the method under test. 916 */ 917 checkSubclassingIgnoredStatic(...args) { 918 this.checkStaticInvalidReceiver(...args); 919 this.checkStaticReceiverNotCalled(...args); 920 this.checkThisValueNotCalled(...args); 921 }, 922 923 /* 924 * Check that calling the static method with a receiver that's not callable, 925 * still calls the intrinsic constructor. 926 */ 927 checkStaticInvalidReceiver(construct, method, methodArgs, resultAssertions) { 928 function check(value, description) { 929 const result = construct[method].apply(value, methodArgs); 930 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 931 resultAssertions(result); 932 } 933 934 check(undefined, "undefined"); 935 check(null, "null"); 936 check(true, "true"); 937 check("test", "string"); 938 check(Symbol(), "symbol"); 939 check(7, "number"); 940 check(7n, "bigint"); 941 check({}, "Non-callable object"); 942 }, 943 944 /* 945 * Check that calling the static method with a receiver that returns a value 946 * that's not callable, still calls the intrinsic constructor. 947 */ 948 checkStaticReceiverNotCalled(construct, method, methodArgs, resultAssertions) { 949 function check(value, description) { 950 const receiver = function () { 951 return value; 952 }; 953 const result = construct[method].apply(receiver, methodArgs); 954 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 955 resultAssertions(result); 956 } 957 958 check(undefined, "undefined"); 959 check(null, "null"); 960 check(true, "true"); 961 check("test", "string"); 962 check(Symbol(), "symbol"); 963 check(7, "number"); 964 check(7n, "bigint"); 965 check({}, "Non-callable object"); 966 }, 967 968 /* 969 * Check that the receiver isn't called. 970 */ 971 checkThisValueNotCalled(construct, method, methodArgs, resultAssertions) { 972 let called = false; 973 974 class MySubclass extends construct { 975 constructor(...args) { 976 called = true; 977 super(...args); 978 } 979 } 980 981 const result = MySubclass[method](...methodArgs); 982 assert.sameValue(called, false); 983 assert.sameValue(Object.getPrototypeOf(result), construct.prototype); 984 resultAssertions(result); 985 }, 986 987 /* 988 * Check that any calendar-carrying Temporal object has its [[Calendar]] 989 * internal slot read by ToTemporalCalendar, and does not fetch the calendar 990 * by calling getters. 991 */ 992 checkToTemporalCalendarFastPath(func) { 993 const plainDate = new Temporal.PlainDate(2000, 5, 2, "iso8601"); 994 const plainDateTime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601"); 995 const plainMonthDay = new Temporal.PlainMonthDay(5, 2, "iso8601"); 996 const plainYearMonth = new Temporal.PlainYearMonth(2000, 5, "iso8601"); 997 const zonedDateTime = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", "iso8601"); 998 999 [plainDate, plainDateTime, plainMonthDay, plainYearMonth, zonedDateTime].forEach((temporalObject) => { 1000 Object.defineProperty(temporalObject, "calendar", { 1001 get() { 1002 throw new Test262Error("should not get 'calendar' property"); 1003 }, 1004 }); 1005 Object.defineProperty(temporalObject, "calendarId", { 1006 get() { 1007 throw new Test262Error("should not get 'calendarId' property"); 1008 }, 1009 }); 1010 1011 func(temporalObject); 1012 }); 1013 }, 1014 1015 checkToTemporalInstantFastPath(func) { 1016 const actual = []; 1017 const expected = []; 1018 1019 const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, "UTC"); 1020 Object.defineProperty(datetime, "toString", { 1021 get() { 1022 actual.push("get toString"); 1023 return function (options) { 1024 actual.push("call toString"); 1025 return Temporal.ZonedDateTime.prototype.toString.call(this, options); 1026 }; 1027 }, 1028 }); 1029 1030 func(datetime); 1031 assert.compareArray(actual, expected, "toString not called"); 1032 }, 1033 1034 checkToTemporalPlainDateTimeFastPath(func) { 1035 const actual = []; 1036 const expected = []; 1037 1038 const date = new Temporal.PlainDate(2000, 5, 2, "iso8601"); 1039 const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.PlainDate.prototype); 1040 ["year", "month", "monthCode", "day"].forEach((property) => { 1041 Object.defineProperty(date, property, { 1042 get() { 1043 actual.push(`get ${formatPropertyName(property)}`); 1044 const value = prototypeDescrs[property].get.call(this); 1045 return TemporalHelpers.toPrimitiveObserver(actual, value, property); 1046 }, 1047 }); 1048 }); 1049 ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"].forEach((property) => { 1050 Object.defineProperty(date, property, { 1051 get() { 1052 actual.push(`get ${formatPropertyName(property)}`); 1053 return undefined; 1054 }, 1055 }); 1056 }); 1057 Object.defineProperty(date, "calendar", { 1058 get() { 1059 actual.push("get calendar"); 1060 return "iso8601"; 1061 }, 1062 }); 1063 1064 func(date); 1065 assert.compareArray(actual, expected, "property getters not called"); 1066 }, 1067 1068 /* 1069 * observeProperty(calls, object, propertyName, value): 1070 * 1071 * Defines an own property @object.@propertyName with value @value, that 1072 * will log any calls to its accessors to the array @calls. 1073 */ 1074 observeProperty(calls, object, propertyName, value, objectName = "") { 1075 Object.defineProperty(object, propertyName, { 1076 get() { 1077 calls.push(`get ${formatPropertyName(propertyName, objectName)}`); 1078 return value; 1079 }, 1080 set() { 1081 calls.push(`set ${formatPropertyName(propertyName, objectName)}`); 1082 } 1083 }); 1084 }, 1085 1086 /* 1087 * observeMethod(calls, object, propertyName, value): 1088 * 1089 * Defines an own property @object.@propertyName with value @value, that 1090 * will log any calls of @value to the array @calls. 1091 */ 1092 observeMethod(calls, object, propertyName, objectName = "") { 1093 const method = object[propertyName]; 1094 object[propertyName] = function () { 1095 calls.push(`call ${formatPropertyName(propertyName, objectName)}`); 1096 return method.apply(object, arguments); 1097 }; 1098 }, 1099 1100 /* 1101 * Used for substituteMethod to indicate default behavior instead of a 1102 * substituted value 1103 */ 1104 SUBSTITUTE_SKIP: SKIP_SYMBOL, 1105 1106 /* 1107 * substituteMethod(object, propertyName, values): 1108 * 1109 * Defines an own property @object.@propertyName that will, for each 1110 * subsequent call to the method previously defined as 1111 * @object.@propertyName: 1112 * - Call the method, if no more values remain 1113 * - Call the method, if the value in @values for the corresponding call 1114 * is SUBSTITUTE_SKIP 1115 * - Otherwise, return the corresponding value in @value 1116 */ 1117 substituteMethod(object, propertyName, values) { 1118 let calls = 0; 1119 const method = object[propertyName]; 1120 object[propertyName] = function () { 1121 if (calls >= values.length) { 1122 return method.apply(object, arguments); 1123 } else if (values[calls] === SKIP_SYMBOL) { 1124 calls++; 1125 return method.apply(object, arguments); 1126 } else { 1127 return values[calls++]; 1128 } 1129 }; 1130 }, 1131 1132 /* 1133 * propertyBagObserver(): 1134 * Returns an object that behaves like the given propertyBag but tracks Get 1135 * and Has operations on any of its properties, by appending messages to an 1136 * array. If the value of a property in propertyBag is a primitive, the value 1137 * of the returned object's property will additionally be a 1138 * TemporalHelpers.toPrimitiveObserver that will track calls to its toString 1139 * and valueOf methods in the same array. This is for the purpose of testing 1140 * order of operations that are observable from user code. objectName is used 1141 * in the log. 1142 * If skipToPrimitive is given, it must be an array of property keys. Those 1143 * properties will not have a TemporalHelpers.toPrimitiveObserver returned, 1144 * and instead just be returned directly. 1145 */ 1146 propertyBagObserver(calls, propertyBag, objectName, skipToPrimitive) { 1147 return new Proxy(propertyBag, { 1148 ownKeys(target) { 1149 calls.push(`ownKeys ${objectName}`); 1150 return Reflect.ownKeys(target); 1151 }, 1152 getOwnPropertyDescriptor(target, key) { 1153 calls.push(`getOwnPropertyDescriptor ${formatPropertyName(key, objectName)}`); 1154 return Reflect.getOwnPropertyDescriptor(target, key); 1155 }, 1156 get(target, key, receiver) { 1157 calls.push(`get ${formatPropertyName(key, objectName)}`); 1158 const result = Reflect.get(target, key, receiver); 1159 if (result === undefined) { 1160 return undefined; 1161 } 1162 if ((result !== null && typeof result === "object") || typeof result === "function") { 1163 return result; 1164 } 1165 if (skipToPrimitive && skipToPrimitive.indexOf(key) >= 0) { 1166 return result; 1167 } 1168 return TemporalHelpers.toPrimitiveObserver(calls, result, `${formatPropertyName(key, objectName)}`); 1169 }, 1170 has(target, key) { 1171 calls.push(`has ${formatPropertyName(key, objectName)}`); 1172 return Reflect.has(target, key); 1173 }, 1174 }); 1175 }, 1176 1177 /* 1178 * Returns an object that will append logs of any Gets or Calls of its valueOf 1179 * or toString properties to the array calls. Both valueOf and toString will 1180 * return the actual primitiveValue. propertyName is used in the log. 1181 */ 1182 toPrimitiveObserver(calls, primitiveValue, propertyName) { 1183 return { 1184 get valueOf() { 1185 calls.push(`get ${propertyName}.valueOf`); 1186 return function () { 1187 calls.push(`call ${propertyName}.valueOf`); 1188 return primitiveValue; 1189 }; 1190 }, 1191 get toString() { 1192 calls.push(`get ${propertyName}.toString`); 1193 return function () { 1194 calls.push(`call ${propertyName}.toString`); 1195 if (primitiveValue === undefined) return undefined; 1196 return primitiveValue.toString(); 1197 }; 1198 }, 1199 }; 1200 }, 1201 1202 /* 1203 * An object containing further methods that return arrays of ISO strings, for 1204 * testing parsers. 1205 */ 1206 ISO: { 1207 /* 1208 * PlainMonthDay strings that are not valid. 1209 */ 1210 plainMonthDayStringsInvalid() { 1211 return [ 1212 "11-18junk", 1213 "11-18[u-ca=gregory]", 1214 "11-18[u-ca=hebrew]", 1215 "11-18[U-CA=iso8601]", 1216 "11-18[u-CA=iso8601]", 1217 "11-18[FOO=bar]", 1218 "-999999-01-01[u-ca=gregory]", 1219 "-999999-01-01[u-ca=chinese]", 1220 "+999999-01-01[u-ca=gregory]", 1221 "+999999-01-01[u-ca=chinese]", 1222 ]; 1223 }, 1224 1225 /* 1226 * PlainMonthDay strings that are valid and that should produce October 1st. 1227 */ 1228 plainMonthDayStringsValid() { 1229 return [ 1230 "10-01", 1231 "1001", 1232 "1965-10-01", 1233 "1976-10-01T152330.1+00:00", 1234 "19761001T15:23:30.1+00:00", 1235 "1976-10-01T15:23:30.1+0000", 1236 "1976-10-01T152330.1+0000", 1237 "19761001T15:23:30.1+0000", 1238 "19761001T152330.1+00:00", 1239 "19761001T152330.1+0000", 1240 "+001976-10-01T152330.1+00:00", 1241 "+0019761001T15:23:30.1+00:00", 1242 "+001976-10-01T15:23:30.1+0000", 1243 "+001976-10-01T152330.1+0000", 1244 "+0019761001T15:23:30.1+0000", 1245 "+0019761001T152330.1+00:00", 1246 "+0019761001T152330.1+0000", 1247 "1976-10-01T15:23:00", 1248 "1976-10-01T15:23", 1249 "1976-10-01T15", 1250 "1976-10-01", 1251 "--10-01", 1252 "--1001", 1253 "-999999-10-01", 1254 "-999999-10-01[u-ca=iso8601]", 1255 "+999999-10-01", 1256 "+999999-10-01[u-ca=iso8601]", 1257 ]; 1258 }, 1259 1260 /* 1261 * PlainTime strings that may be mistaken for PlainMonthDay or 1262 * PlainYearMonth strings, and so require a time designator. 1263 */ 1264 plainTimeStringsAmbiguous() { 1265 const ambiguousStrings = [ 1266 "2021-12", // ambiguity between YYYY-MM and HHMM-UU 1267 "2021-12[-12:00]", // ditto, TZ does not disambiguate 1268 "1214", // ambiguity between MMDD and HHMM 1269 "0229", // ditto, including MMDD that doesn't occur every year 1270 "1130", // ditto, including DD that doesn't occur in every month 1271 "12-14", // ambiguity between MM-DD and HH-UU 1272 "12-14[-14:00]", // ditto, TZ does not disambiguate 1273 "202112", // ambiguity between YYYYMM and HHMMSS 1274 "202112[UTC]", // ditto, TZ does not disambiguate 1275 ]; 1276 // Adding a calendar annotation to one of these strings must not cause 1277 // disambiguation in favour of time. 1278 const stringsWithCalendar = ambiguousStrings.map((s) => s + "[u-ca=iso8601]"); 1279 return ambiguousStrings.concat(stringsWithCalendar); 1280 }, 1281 1282 /* 1283 * PlainTime strings that are of similar form to PlainMonthDay and 1284 * PlainYearMonth strings, but are not ambiguous due to components that 1285 * aren't valid as months or days. 1286 */ 1287 plainTimeStringsUnambiguous() { 1288 return [ 1289 "2021-13", // 13 is not a month 1290 "202113", // ditto 1291 "2021-13[-13:00]", // ditto 1292 "202113[-13:00]", // ditto 1293 "0000-00", // 0 is not a month 1294 "000000", // ditto 1295 "0000-00[UTC]", // ditto 1296 "000000[UTC]", // ditto 1297 "1314", // 13 is not a month 1298 "13-14", // ditto 1299 "1232", // 32 is not a day 1300 "0230", // 30 is not a day in February 1301 "0631", // 31 is not a day in June 1302 "0000", // 0 is neither a month nor a day 1303 "00-00", // ditto 1304 ]; 1305 }, 1306 1307 /* 1308 * PlainYearMonth-like strings that are not valid. 1309 */ 1310 plainYearMonthStringsInvalid() { 1311 return [ 1312 "2020-13", 1313 "1976-11[u-ca=gregory]", 1314 "1976-11[u-ca=hebrew]", 1315 "1976-11[U-CA=iso8601]", 1316 "1976-11[u-CA=iso8601]", 1317 "1976-11[FOO=bar]", 1318 "+999999-01", 1319 "-999999-01", 1320 ]; 1321 }, 1322 1323 /* 1324 * PlainYearMonth-like strings that are valid and should produce November 1325 * 1976 in the ISO 8601 calendar. 1326 */ 1327 plainYearMonthStringsValid() { 1328 return [ 1329 "1976-11", 1330 "1976-11-10", 1331 "1976-11-01T09:00:00+00:00", 1332 "1976-11-01T00:00:00+05:00", 1333 "197611", 1334 "+00197611", 1335 "1976-11-18T15:23:30.1-02:00", 1336 "1976-11-18T152330.1+00:00", 1337 "19761118T15:23:30.1+00:00", 1338 "1976-11-18T15:23:30.1+0000", 1339 "1976-11-18T152330.1+0000", 1340 "19761118T15:23:30.1+0000", 1341 "19761118T152330.1+00:00", 1342 "19761118T152330.1+0000", 1343 "+001976-11-18T152330.1+00:00", 1344 "+0019761118T15:23:30.1+00:00", 1345 "+001976-11-18T15:23:30.1+0000", 1346 "+001976-11-18T152330.1+0000", 1347 "+0019761118T15:23:30.1+0000", 1348 "+0019761118T152330.1+00:00", 1349 "+0019761118T152330.1+0000", 1350 "1976-11-18T15:23", 1351 "1976-11-18T15", 1352 "1976-11-18", 1353 ]; 1354 }, 1355 1356 /* 1357 * PlainYearMonth-like strings that are valid and should produce November of 1358 * the ISO year -9999. 1359 */ 1360 plainYearMonthStringsValidNegativeYear() { 1361 return [ 1362 "-009999-11", 1363 ]; 1364 }, 1365 } 1366 };