mirror of
https://github.com/tc39/test262.git
synced 2025-04-08 19:35:28 +02:00
Tests for computing PlainYearMonth addition and subtraction in correct calendar space
https://github.com/tc39/proposal-temporal/pull/2003 is a normative change that reached consensus at the March 2022 TC39 plenary meeting. This adds tests that verify the new spec text is implemented correctly, performing arithmetic on a PlainYearMonth instance that would previously have thrown an error if it was implemented as written.
This commit is contained in:
parent
c58ac691eb
commit
833a784f20
147
test/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js
vendored
Normal file
147
test/built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plainyearmonth.prototype.add
|
||||
description: >
|
||||
Calls calendar's dateFromFields method to obtain a start date for the
|
||||
operation, based on the sign of the duration
|
||||
info: |
|
||||
8. Let _fields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»).
|
||||
9. Let _sign_ be ! DurationSign(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _balanceResult_.[[Days]], 0, 0, 0, 0, 0, 0).
|
||||
10. If _sign_ < 0, then
|
||||
a. Let _dayFromCalendar_ be ? CalendarDaysInMonth(_calendar_, _yearMonth_).
|
||||
b. Let _day_ be ? ToPositiveInteger(_dayFromCalendar_).
|
||||
11. Else,
|
||||
a. Let _day_ be 1.
|
||||
12. Perform ! CreateDataPropertyOrThrow(_fields_, *"day"*, _day_).
|
||||
13. Let _date_ be ? DateFromFields(_calendar_, _fields_, *undefined*).
|
||||
includes: [deepEqual.js, temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
class CustomCalendar extends Temporal.Calendar {
|
||||
constructor() {
|
||||
super("iso8601");
|
||||
this.dateFromFieldsCalls = [];
|
||||
}
|
||||
year(date) {
|
||||
// years in this calendar start and end on the same day as ISO 8601 years
|
||||
return date.getISOFields().isoYear;
|
||||
}
|
||||
month(date) {
|
||||
// this calendar has 10 months of 36 days each, plus an 11th month of 5 or 6
|
||||
const { isoYear, isoMonth, isoDay } = date.getISOFields();
|
||||
const isoDate = new Temporal.PlainDate(isoYear, isoMonth, isoDay);
|
||||
return Math.floor((isoDate.dayOfYear - 1) / 36) + 1;
|
||||
}
|
||||
monthCode(date) {
|
||||
return "M" + this.month(date).toString().padStart(2, "0");
|
||||
}
|
||||
day(date) {
|
||||
return (date.dayOfYear - 1) % 36 + 1;
|
||||
}
|
||||
daysInMonth(date) {
|
||||
if (this.month(date) < 11) return 36;
|
||||
return this.daysInYear(date) - 360;
|
||||
}
|
||||
_dateFromFieldsImpl({ year, month, monthCode, day }) {
|
||||
if (year === undefined) throw new TypeError("year required");
|
||||
if (month === undefined && monthCode === undefined) throw new TypeError("one of month or monthCode required");
|
||||
if (month !== undefined && month < 1) throw new RangeError("month < 1");
|
||||
if (day === undefined) throw new TypeError("day required");
|
||||
|
||||
if (monthCode !== undefined) {
|
||||
const numberPart = +(monthCode.slice(1));
|
||||
if ("M" + `${numberPart}`.padStart(2, "0") !== monthCode) throw new RangeError("invalid monthCode");
|
||||
if (month === undefined) {
|
||||
month = numberPart;
|
||||
} else if (month !== numberPart) {
|
||||
throw new RangeError("month and monthCode must match");
|
||||
}
|
||||
}
|
||||
|
||||
const isoDayOfYear = (month - 1) * 36 + day;
|
||||
return new Temporal.PlainDate(year, 1, 1).add({ days: isoDayOfYear - 1 }).withCalendar(this);
|
||||
}
|
||||
dateFromFields(...args) {
|
||||
this.dateFromFieldsCalls.push(args);
|
||||
return this._dateFromFieldsImpl(...args);
|
||||
}
|
||||
yearMonthFromFields(fields, options) {
|
||||
const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, day: 1 }, options).getISOFields();
|
||||
return new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay);
|
||||
}
|
||||
monthDayFromFields(fields, options) {
|
||||
const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, year: 2000 }, options).getISOFields();
|
||||
return new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear);
|
||||
}
|
||||
dateAdd(date, duration, options) {
|
||||
if (duration.months) throw new Error("adding months not implemented in this test");
|
||||
return super.dateAdd(date, duration, options);
|
||||
}
|
||||
toString() {
|
||||
return "thirty-six";
|
||||
}
|
||||
}
|
||||
|
||||
const calendar = new CustomCalendar();
|
||||
const month2 = Temporal.PlainYearMonth.from({ year: 2022, month: 2, calendar });
|
||||
const lessThanOneMonth = new Temporal.Duration(0, 0, 0, 35);
|
||||
const oneMonth = new Temporal.Duration(0, 0, 0, 36);
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.add(lessThanOneMonth),
|
||||
2022, 2, "M02",
|
||||
"adding positive less than one month's worth of days yields the same month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 1 },
|
||||
"first day of month 2 passed to dateFromFields when adding positive duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.add(oneMonth),
|
||||
2022, 3, "M03",
|
||||
"adding positive one month's worth of days yields the following month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 1 },
|
||||
"first day of month 2 passed to dateFromFields when adding positive duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.add(lessThanOneMonth.negated()),
|
||||
2022, 2, "M02",
|
||||
"adding negative less than one month's worth of days yields the same month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 36 },
|
||||
"last day of month 2 passed to dateFromFields when adding negative duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.add(oneMonth.negated()),
|
||||
2022, 1, "M01",
|
||||
"adding negative one month's worth of days yields the previous month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 36 },
|
||||
"last day of month 2 passed to dateFromFields when adding negative duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
147
test/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js
vendored
Normal file
147
test/built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plainyearmonth.prototype.subtract
|
||||
description: >
|
||||
Calls calendar's dateFromFields method to obtain a start date for the
|
||||
operation, based on the sign of the duration
|
||||
info: |
|
||||
9. Let _fields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»).
|
||||
10. Let _sign_ be ! DurationSign(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _balanceResult_.[[Days]], 0, 0, 0, 0, 0, 0).
|
||||
11. If _sign_ < 0, then
|
||||
a. Let _dayFromCalendar_ be ? CalendarDaysInMonth(_calendar_, _yearMonth_).
|
||||
b. Let _day_ be ? ToPositiveInteger(_dayFromCalendar_).
|
||||
12. Else,
|
||||
a. Let _day_ be 1.
|
||||
13. Perform ! CreateDataPropertyOrThrow(_fields_, *"day"*, _day_).
|
||||
14. Let _date_ be ? DateFromFields(_calendar_, _fields_, *undefined*).
|
||||
includes: [deepEqual.js, temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
class CustomCalendar extends Temporal.Calendar {
|
||||
constructor() {
|
||||
super("iso8601");
|
||||
this.dateFromFieldsCalls = [];
|
||||
}
|
||||
year(date) {
|
||||
// years in this calendar start and end on the same day as ISO 8601 years
|
||||
return date.getISOFields().isoYear;
|
||||
}
|
||||
month(date) {
|
||||
// this calendar has 10 months of 36 days each, plus an 11th month of 5 or 6
|
||||
const { isoYear, isoMonth, isoDay } = date.getISOFields();
|
||||
const isoDate = new Temporal.PlainDate(isoYear, isoMonth, isoDay);
|
||||
return Math.floor((isoDate.dayOfYear - 1) / 36) + 1;
|
||||
}
|
||||
monthCode(date) {
|
||||
return "M" + this.month(date).toString().padStart(2, "0");
|
||||
}
|
||||
day(date) {
|
||||
return (date.dayOfYear - 1) % 36 + 1;
|
||||
}
|
||||
daysInMonth(date) {
|
||||
if (this.month(date) < 11) return 36;
|
||||
return this.daysInYear(date) - 360;
|
||||
}
|
||||
_dateFromFieldsImpl({ year, month, monthCode, day }) {
|
||||
if (year === undefined) throw new TypeError("year required");
|
||||
if (month === undefined && monthCode === undefined) throw new TypeError("one of month or monthCode required");
|
||||
if (month !== undefined && month < 1) throw new RangeError("month < 1");
|
||||
if (day === undefined) throw new TypeError("day required");
|
||||
|
||||
if (monthCode !== undefined) {
|
||||
const numberPart = +(monthCode.slice(1));
|
||||
if ("M" + `${numberPart}`.padStart(2, "0") !== monthCode) throw new RangeError("invalid monthCode");
|
||||
if (month === undefined) {
|
||||
month = numberPart;
|
||||
} else if (month !== numberPart) {
|
||||
throw new RangeError("month and monthCode must match");
|
||||
}
|
||||
}
|
||||
|
||||
const isoDayOfYear = (month - 1) * 36 + day;
|
||||
return new Temporal.PlainDate(year, 1, 1).add({ days: isoDayOfYear - 1 }).withCalendar(this);
|
||||
}
|
||||
dateFromFields(...args) {
|
||||
this.dateFromFieldsCalls.push(args);
|
||||
return this._dateFromFieldsImpl(...args);
|
||||
}
|
||||
yearMonthFromFields(fields, options) {
|
||||
const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, day: 1 }, options).getISOFields();
|
||||
return new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay);
|
||||
}
|
||||
monthDayFromFields(fields, options) {
|
||||
const { isoYear, isoMonth, isoDay } = this._dateFromFieldsImpl({ ...fields, year: 2000 }, options).getISOFields();
|
||||
return new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear);
|
||||
}
|
||||
dateAdd(date, duration, options) {
|
||||
if (duration.months) throw new Error("adding months not implemented in this test");
|
||||
return super.dateAdd(date, duration, options);
|
||||
}
|
||||
toString() {
|
||||
return "thirty-six";
|
||||
}
|
||||
}
|
||||
|
||||
const calendar = new CustomCalendar();
|
||||
const month2 = Temporal.PlainYearMonth.from({ year: 2022, month: 2, calendar });
|
||||
const lessThanOneMonth = new Temporal.Duration(0, 0, 0, 35);
|
||||
const oneMonth = new Temporal.Duration(0, 0, 0, 36);
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.subtract(lessThanOneMonth),
|
||||
2022, 2, "M02",
|
||||
"subtracting positive less than one month's worth of days yields the same month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 36 },
|
||||
"last day of month 2 passed to dateFromFields when subtracting positive duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.subtract(oneMonth),
|
||||
2022, 1, "M01",
|
||||
"subtracting positive one month's worth of days yields the previous month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 36 },
|
||||
"last day of month 2 passed to dateFromFields when subtracting positive duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.subtract(lessThanOneMonth.negated()),
|
||||
2022, 2, "M02",
|
||||
"subtracting negative less than one month's worth of days yields the same month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 1 },
|
||||
"first day of month 2 passed to dateFromFields when subtracting negative duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
||||
|
||||
calendar.dateFromFieldsCalls = [];
|
||||
TemporalHelpers.assertPlainYearMonth(
|
||||
month2.subtract(oneMonth.negated()),
|
||||
2022, 3, "M03",
|
||||
"subtracting negative one month's worth of days yields the following month"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls.length, 1, "dateFromFields was called");
|
||||
assert.deepEqual(
|
||||
calendar.dateFromFieldsCalls[0][0],
|
||||
{ year: 2022, month: 2, monthCode: "M02", day: 1 },
|
||||
"first day of month 2 passed to dateFromFields when subtracting negative duration"
|
||||
);
|
||||
assert.sameValue(calendar.dateFromFieldsCalls[0][1], undefined, "undefined options passed");
|
Loading…
x
Reference in New Issue
Block a user