Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Temporal: Update PlainMonthDay-related tests #3899

Merged
merged 5 commits into from
Oct 26, 2023

Conversation

gibson042
Copy link
Contributor

As of tc39/proposal-temporal#2500 , year is always optional for the ISO 8601 calendar.

Copy link
Contributor Author

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for not separating this into meaningful commits; I have added PR comments to categorize.

assert.throws(TypeError, () => cal.monthDayFromFields({ monthCode: "M12" }), "day is required with monthCode");
assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, month: 12 }), "day is required with year and month");
assert.throws(TypeError, () => cal.monthDayFromFields({ month: 1, day: 17 }), "year is required if month is present");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is no longer appropriate because monthDayFromFields({ month, day }) is acceptable in the ISO 8601 calendar.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(case 2.ii)

Comment on lines +30 to +40
options.forEach((opt) => {
const optionsDesc = opt && JSON.stringify(opt);
result = cal.monthDayFromFields({ year: 2021, month: 7, day: 3 }, opt);
TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "month 7, day 3, with year");
TemporalHelpers.assertPlainMonthDay(result, "M07", 3, `month 7, day 3, with year, options = ${optionsDesc}`);
result = cal.monthDayFromFields({ year: 2021, month: 12, day: 31 }, opt);
TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "month 12, day 31, with year");
TemporalHelpers.assertPlainMonthDay(result, "M12", 31, `month 12, day 31, with year, options = ${optionsDesc}`);
result = cal.monthDayFromFields({ monthCode: "M07", day: 3 }, opt);
TemporalHelpers.assertPlainMonthDay(result, "M07", 3, "monthCode M07, day 3");
TemporalHelpers.assertPlainMonthDay(result, "M07", 3, `monthCode M07, day 3, options = ${optionsDesc}`);
result = cal.monthDayFromFields({ monthCode: "M12", day: 31 }, opt);
TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "monthCode M12, day 31");
TemporalHelpers.assertPlainMonthDay(result, "M12", 31, `monthCode M12, day 31, options = ${optionsDesc}`);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This DRYs out the testing and increases coverage but does not change expectations.

},
};
assert.throws(TypeError, () => instance.monthDayFromFields(monthWithoutYear), "year/month should be checked after fetching but before resolving the month code");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is no longer appropriate because monthDayFromFields({ month, day }) is acceptable in the ISO 8601 calendar, but wasn't actually material to the test so has been replaced with assertions against a full complement of property access spies that also subsume { day: 1 }.

Comment on lines -47 to -61
assert.throws(
RangeError,
() => cal.monthDayFromFields({ year: 2021, month: -99999, day: 1 }, opt),
"negative month -99999 is out of range even with overflow constrain"
)
assert.throws(
RangeError,
() => cal.monthDayFromFields({ year: 2021, month: -1, day: 1 }, opt),
"negative month -1 is out of range even with overflow constrain"
)
assert.throws(
RangeError,
() => cal.monthDayFromFields({ year: 2021, month: 0, day: 1 }, opt),
"month zero is out of range even with overflow constrain"
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These have been moved to the first forEach.

Comment on lines +43 to +44
result = cal.monthDayFromFields({ month, day: daysInMonth });
TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth, `month ${month}, day ${daysInMonth}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This monthDayFromFields would previously have been expected to throw.

Copy link
Contributor

@ptomato ptomato Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: case 2.ii from tc39/proposal-temporal#2664

Comment on lines +47 to +49
assert.throws(RangeError,
() => cal.monthDayFromFields({ month, day }, { overflow: "reject" }),
`Day ${day} is out of range for month ${month} with overflow: reject`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This monthDayFromFields would previously have been expected to throw, but for a different reason.

`Day ${day} is out of range for monthCode ${monthCode} with overflow: reject`);
});

[ ["month", 2], ["monthCode", "M02"] ].forEach(([ name, value ]) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new coverage for year sensitivity (but use of monthCode would have been expected to ignore year before tc39/proposal-temporal#2497 ).

Comment on lines 15 to 19
assert.throws(TypeError, () => Temporal.PlainMonthDay.from({ month: 11, day: 18, calendar: "iso8601" }), "month, day with calendar");

if (TemporalHelpers.nonDefaultCalendarId) {
assert.throws(TypeError, () => Temporal.PlainMonthDay.from({ month: 11, day: 18, calendar: TemporalHelpers.nonDefaultCalendarId }), "month, day with non-iso8601 calendar");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected failure is now dependent upon use of a non–ISO-8601 calendar.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that this is a change we want to make. See tc39/proposal-temporal#2663 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case 3.ii

Comment on lines +16 to -19
TemporalHelpers.assertPlainMonthDay(md.with({ month: 12 }),
"M12", 15, "with({month})");

TemporalHelpers.assertPlainMonthDay(md.with({ monthCode: "M12" }),
"M12", 15, "with({monthCode})");

assert.throws(TypeError, () => md.with({ month: 12 }), "with({month})");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This with would previously have been expected to throw, but no longer does in the ISO 8601 calendar.

Copy link
Contributor

@ptomato ptomato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanatory comments, they really made this easier.
These look good, I noticed one typo in an assertion message and I'd like to move the non-ISO-calendar-dependent tests into test/intl402/.

TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth, `month ${month}, day ${daysInMonth}`);

result = cal.monthDayFromFields({ monthCode, day: daysInMonth });
TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth, `monthCode ${monthCode}, day ${daysInMonth}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case 2.i

@ptomato
Copy link
Contributor

ptomato commented Sep 18, 2023

So, I feel pretty strongly about not having the tests for nonDefaultCalendarID execute conditionally, because we generally don't like conditionally executing tests, but also particularly because it's not what we've done in the rest of the Temporal test coverage.

As a way forward, could I propose the following? Let's move the nonDefaultCalendarID stuff to the test/intl402/ folders for now and just pick a calendar ID that's likely to be implemented, like "hebrew" or "gregory". Then separately work on migrating all of the tests that require a non-ISO8601 calendar but aren't dependent on it being any particular calendar, to use a new flag in the front matter. Straw proposal something like flags: [non-iso-calendar]. Runners that support this flag should provide a $262.nonISOCalendarID property which is a string calendar ID, and otherwise skip the test.

Also I'd suggest making a couple of files (one in test/built-ins/ and one in test/intl402/) that explicitly test each case that we listed in tc39/proposal-temporal#2664. It's mostly points 1, 2, and 3 that we have coverage for, 4 and 5 not so much (unless it already exists elsewhere and I don't see it.)

@ptomato
Copy link
Contributor

ptomato commented Sep 18, 2023

Forgot to add, I realize that's a lot of refactoring to ask, so if that'll be a prohibitive time sink, let me know and I can do it.

@gibson042
Copy link
Contributor Author

So, I feel pretty strongly about not having the tests for nonDefaultCalendarID execute conditionally, because we generally don't like conditionally executing tests, but also particularly because it's not what we've done in the rest of the Temporal test coverage.

Allright, I don't object.

As a way forward, could I propose the following? Let's move the nonDefaultCalendarID stuff to the test/intl402/ folders for now and just pick a calendar ID that's likely to be implemented, like "hebrew" or "gregory". Then separately work on migrating all of the tests that require a non-ISO8601 calendar but aren't dependent on it being any particular calendar, to use a new flag in the front matter. Straw proposal something like flags: [non-iso-calendar]. Runners that support this flag should provide a $262.nonISOCalendarID property which is a string calendar ID, and otherwise skip the test.

That's probably overkill, but I support the general concept.

Also I'd suggest making a couple of files (one in test/built-ins/ and one in test/intl402/) that explicitly test each case that we listed in tc39/proposal-temporal#2664. It's mostly points 1, 2, and 3 that we have coverage for, 4 and 5 not so much (unless it already exists elsewhere and I don't see it.)

Hmm, I'm not sure how to structure that but I also support it. I think I am going to avail myself of your offer to refactor.

@ptomato
Copy link
Contributor

ptomato commented Sep 19, 2023

I think I am going to avail myself of your offer to refactor.

All good, I'll do that tomorrow.

@@ -0,0 +1,31 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to verify that a custom calendar can do its own verification.

Comment on lines -6 to +17
description: Throw a RangeError if only one of era/eraYear fields is present
description: Throw a TypeError if only one of era/eraYear fields is present
features: [Temporal]
---*/

const base = { year: 2000, month: 5, day: 2, era: 'ce' };
const instance = new Temporal.Calendar('gregory');
assert.throws(RangeError, () => {
assert.throws(TypeError, () => {
instance.dateFromFields({ ...base });
});

const base2 = { year: 2000, month: 5, day: 2, eraYear: 1 };
assert.throws(RangeError, () => {
assert.throws(TypeError, () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and the similar change in yearMonthFromFields) is an additional pre-existing bug that I found while working on this. CalendarResolveFields says "The operation throws a TypeError exception if the properties of fields are internally inconsistent within the calendar or insufficient to identify a unique instance of type in the calendar," but we were expecting a RangeError here.

@@ -1,19 +0,0 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to fields-underspecified.js because I added more cases that were not specifically about era/eraYear.

@ptomato
Copy link
Contributor

ptomato commented Sep 19, 2023

@gibson042 Have a look at the new commits and let me know what you think!

While working on this I uncovered an additional bug in the tests, see comments for more information.

@ptomato
Copy link
Contributor

ptomato commented Oct 2, 2023

@gibson042 I'm happy with the state of this now, but could you take a quick look at what I added on top of your work? Feel free to click the merge button if you're OK with it.

Copy link
Contributor Author

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ptomato LGTM, thanks for your help (and your patience)!

gibson042 and others added 5 commits October 26, 2023 12:34
As of tc39/proposal-temporal#2500 ,
year is always optional for the ISO 8601 calendar.
We'll do this for now, then separately work on migrating all of the tests
that require a non-ISO8601 calendar but aren't dependent on it being any
particular calendar.
Built-in non-ISO calendars require either monthCode/day, or month/day plus
some form of year specification.

This adds test coverage for each of the categories listed in
tc39/proposal-temporal#2664, of which some must
currently reside in the test/intl402/ folders.
These tests were incorrect, in checking for a RangeError when only one of
the era/eraYear fields were given. From CalendarResolveFields:

"The operation throws a *TypeError* exception if the properties of
_fields_ are internally inconsistent within the calendar or insufficient
to identify a unique instance of _type_ in the calendar."
@gibson042 gibson042 enabled auto-merge (rebase) October 26, 2023 16:35
@gibson042 gibson042 merged commit 892a5dc into tc39:main Oct 26, 2023
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants