Skip to content

Commit

Permalink
Temporal: Move some round() and total() tests out of staging
Browse files Browse the repository at this point in the history
Including tests for every possible combination of largest and smallest
unit, for each type of relativeTo (undefined, PlainDate, ZonedDateTime).
  • Loading branch information
ptomato authored and Ms2ger committed May 14, 2024
1 parent 96e31e7 commit e02220b
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 273 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.round
description: Test for all combinations of largestUnit and smallestUnit with relativeTo
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const duration = new Temporal.Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5);
const plainRelativeTo = new Temporal.PlainDate(2000, 1, 1);
const zonedRelativeTo = new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, "UTC");

const exactResults = {
years: {
years: [6],
months: [5, 6],
weeks: [5, 6, 1],
days: [5, 6, 0, 10],
hours: [5, 6, 0, 10, 5],
minutes: [5, 6, 0, 10, 5, 5],
seconds: [5, 6, 0, 10, 5, 5, 5],
milliseconds: [5, 6, 0, 10, 5, 5, 5, 5],
microseconds: [5, 6, 0, 10, 5, 5, 5, 5, 5],
nanoseconds: [5, 6, 0, 10, 5, 5, 5, 5, 5, 5],
},
months: {
months: [0, 66],
weeks: [0, 66, 1],
days: [0, 66, 0, 10],
hours: [0, 66, 0, 10, 5],
minutes: [0, 66, 0, 10, 5, 5],
seconds: [0, 66, 0, 10, 5, 5, 5],
milliseconds: [0, 66, 0, 10, 5, 5, 5, 5],
microseconds: [0, 66, 0, 10, 5, 5, 5, 5, 5],
nanoseconds: [0, 66, 0, 10, 5, 5, 5, 5, 5, 5],
},
weeks: {
weeks: [0, 0, 288],
days: [0, 0, 288, 2],
hours: [0, 0, 288, 2, 5],
minutes: [0, 0, 288, 2, 5, 5],
seconds: [0, 0, 288, 2, 5, 5, 5],
milliseconds: [0, 0, 288, 2, 5, 5, 5, 5],
microseconds: [0, 0, 288, 2, 5, 5, 5, 5, 5],
nanoseconds: [0, 0, 288, 2, 5, 5, 5, 5, 5, 5],
},
days: {
days: [0, 0, 0, 2018],
hours: [0, 0, 0, 2018, 5],
minutes: [0, 0, 0, 2018, 5, 5],
seconds: [0, 0, 0, 2018, 5, 5, 5],
milliseconds: [0, 0, 0, 2018, 5, 5, 5, 5],
microseconds: [0, 0, 0, 2018, 5, 5, 5, 5, 5],
nanoseconds: [0, 0, 0, 2018, 5, 5, 5, 5, 5, 5],
},
hours: {
hours: [0, 0, 0, 0, 48437],
minutes: [0, 0, 0, 0, 48437, 5],
seconds: [0, 0, 0, 0, 48437, 5, 5],
milliseconds: [0, 0, 0, 0, 48437, 5, 5, 5],
microseconds: [0, 0, 0, 0, 48437, 5, 5, 5, 5],
nanoseconds: [0, 0, 0, 0, 48437, 5, 5, 5, 5, 5],
},
minutes: {
minutes: [0, 0, 0, 0, 0, 2906225],
seconds: [0, 0, 0, 0, 0, 2906225, 5],
milliseconds: [0, 0, 0, 0, 0, 2906225, 5, 5],
microseconds: [0, 0, 0, 0, 0, 2906225, 5, 5, 5],
nanoseconds: [0, 0, 0, 0, 0, 2906225, 5, 5, 5, 5],
},
seconds: {
seconds: [0, 0, 0, 0, 0, 0, 174373505],
milliseconds: [0, 0, 0, 0, 0, 0, 174373505, 5],
microseconds: [0, 0, 0, 0, 0, 0, 174373505, 5, 5],
nanoseconds: [0, 0, 0, 0, 0, 0, 174373505, 5, 5, 5],
},
milliseconds: {
milliseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005],
microseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005, 5],
nanoseconds: [0, 0, 0, 0, 0, 0, 0, 174373505005, 5, 5],
},
microseconds: {
microseconds: [0, 0, 0, 0, 0, 0, 0, 0, 174373505005005],
nanoseconds: [0, 0, 0, 0, 0, 0, 0, 0, 174373505005005, 5],
},
};
for (const [largestUnit, entry] of Object.entries(exactResults)) {
for (const [smallestUnit, expected] of Object.entries(entry)) {
for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
const [y, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected;
TemporalHelpers.assertDuration(
duration.round({ largestUnit, smallestUnit, relativeTo }),
y, mon, w, d, h, min, s, ms, µs, ns,
`Combination of largestUnit ${largestUnit} and smallestUnit ${smallestUnit}, relative to ${relativeTo}`
);
}
}
}

// 174373505005005005 is not a safe integer.
// ℝ(𝔽(174373505005005005)) == 174373505005004992

for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
TemporalHelpers.assertDuration(
duration.round({ largestUnit: "nanoseconds", smallestUnit: "nanoseconds", relativeTo }),
0, 0, 0, 0, 0, 0, 0, 0, 0, 174373505005004992,
`Combination of largestUnit nanoseconds and smallestUnit nanoseconds, with precision loss, relative to ${relativeTo}`
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.round
description: Test for all combinations of largestUnit and smallestUnit without relativeTo
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const duration = new Temporal.Duration(0, 0, 0, 5, 5, 5, 5, 5, 5, 5);

const exactResults = {
days: {
days: [5],
hours: [5, 5],
minutes: [5, 5, 5],
seconds: [5, 5, 5, 5],
milliseconds: [5, 5, 5, 5, 5],
microseconds: [5, 5, 5, 5, 5, 5],
nanoseconds: [5, 5, 5, 5, 5, 5, 5],
},
hours: {
hours: [0, 125],
minutes: [0, 125, 5],
seconds: [0, 125, 5, 5],
milliseconds: [0, 125, 5, 5, 5],
microseconds: [0, 125, 5, 5, 5, 5],
nanoseconds: [0, 125, 5, 5, 5, 5, 5],
},
minutes: {
minutes: [0, 0, 7505],
seconds: [0, 0, 7505, 5],
milliseconds: [0, 0, 7505, 5, 5],
microseconds: [0, 0, 7505, 5, 5, 5],
nanoseconds: [0, 0, 7505, 5, 5, 5, 5],
},
seconds: {
seconds: [0, 0, 0, 450305],
milliseconds: [0, 0, 0, 450305, 5],
microseconds: [0, 0, 0, 450305, 5, 5],
nanoseconds: [0, 0, 0, 450305, 5, 5, 5],
},
milliseconds: {
milliseconds: [0, 0, 0, 0, 450305005],
microseconds: [0, 0, 0, 0, 450305005, 5],
nanoseconds: [0, 0, 0, 0, 450305005, 5, 5],
},
microseconds: {
microseconds: [0, 0, 0, 0, 0, 450305005005],
nanoseconds: [0, 0, 0, 0, 0, 450305005005, 5],
},
nanoseconds: {
nanoseconds: [0, 0, 0, 0, 0, 0, 450305005005005],
},
};
for (const [largestUnit, entry] of Object.entries(exactResults)) {
for (const [smallestUnit, expected] of Object.entries(entry)) {
const [d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = expected;
TemporalHelpers.assertDuration(
duration.round({ largestUnit, smallestUnit }),
0, 0, 0, d, h, min, s, ms, µs, ns,
`Combination of largestUnit ${largestUnit} and smallestUnit ${smallestUnit}`
);
}
}
146 changes: 146 additions & 0 deletions test/built-ins/Temporal/Duration/prototype/total/dst-day-length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: >
ZonedDateTime relativeTo affects day length when the duration encompasses a
DST change
includes: [temporalHelpers.js]
features: [Temporal]
---*/

const oneDay = new Temporal.Duration(0, 0, 0, 1);
const oneDayNeg = new Temporal.Duration(0, 0, 0, -1);
const hours12 = new Temporal.Duration(0, 0, 0, 0, 12);
const hours12Neg = new Temporal.Duration(0, 0, 0, 0, -12);
const hours25 = new Temporal.Duration(0, 0, 0, 0, 25);
const hours25Neg = new Temporal.Duration(0, 0, 0, 0, -25);
const hours48 = new Temporal.Duration(0, 0, 0, 0, 48);

const timeZone = TemporalHelpers.springForwardFallBackTimeZone();

const skippedHourDay = new Temporal.ZonedDateTime(
954662400_000_000_000n /* = 2000-04-02T08Z */,
timeZone); /* = 2000-04-02T00-08 in local time */
const repeatedHourDay = new Temporal.ZonedDateTime(
972802800_000_000_000n /* = 2000-10-29T07Z */,
timeZone); /* = 2000-10-29T00-07 in local time */
const inRepeatedHour = new Temporal.ZonedDateTime(
972806400_000_000_000n /* = 2000-10-29T08Z */,
timeZone); /* = 2000-10-29T01-07 in local time */
const oneDayAfterRepeatedHour = new Temporal.ZonedDateTime(
972896400_000_000_000n /* = 2000-10-30T09Z */,
timeZone); /* = 2000-10-30T01-08 in local time */
const beforeSkippedHour = new Temporal.ZonedDateTime(
954585000_000_000_000n /* = 2000-04-01T10:30Z */,
timeZone); /* = 2000-04-01T02:30-08 in local time */
const dayAfterSkippedHour = new Temporal.ZonedDateTime(
954745200_000_000_000n /* = 2000-04-03T07Z */,
timeZone); /* = 2000-04-03T00-07 in local time */
const afterSkippedHour = new Temporal.ZonedDateTime(
954702000_000_000_000n /* = 2000-04-02T19Z */,
timeZone); /* = 2000-04-02T12-07 in local time */
const afterRepeatedHour = new Temporal.ZonedDateTime(
972892800_000_000_000n /* = 2000-10-30T08Z */,
timeZone); /* = 2000-10-30T00-08 in local time */
const afterRepeatedHourSameDay = new Temporal.ZonedDateTime(
972849600_000_000_000n /* = 2000-10-29T20Z */,
timeZone); /* = 2000-10-29T12-08 in local time */
const beforeRepeatedHour = new Temporal.ZonedDateTime(
972716400_000_000_000n /* = 2000-10-28T07Z */,
timeZone); /* = 2000-10-28T00-07 in local time */

assert.sameValue(hours25.total({
unit: "days",
relativeTo: inRepeatedHour
}), 1, "start inside repeated hour, end after: 25 hours = 1 day");

assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: inRepeatedHour
}), 25, "start inside repeated hour, end after: 1 day = 25 hours");

assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: oneDayAfterRepeatedHour
}), -1, "start after repeated hour, end inside: -25 hours = 1 day");

assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: oneDayAfterRepeatedHour
}), -25, "start after repeated hour, end inside: -1 day = -25 hours");

assert.sameValue(hours25.total({
unit: "days",
relativeTo: beforeSkippedHour
}), 24 / 23, "start in normal hour, end in skipped hour: 25 hours = 1 1/23 day");

assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: beforeSkippedHour
}), 24, "start in normal hour, end in skipped hour: 1 day = 24 hours");

assert.sameValue(hours25.total({
unit: "days",
relativeTo: skippedHourDay
}), 13 / 12, "start before skipped hour, end >1 day after: 25 hours = 1 2/24 day");

assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: skippedHourDay
}), 23, "start before skipped hour, end >1 day after: 1 day = 23 hours");

assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: dayAfterSkippedHour
}), -13 / 12, "start after skipped hour, end >1 day before: -25 hours = -1 2/24 day");

assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: dayAfterSkippedHour
}), -23, "start after skipped hour, end >1 day before: -1 day = -23 hours");

assert.sameValue(hours12.total({
unit: "days",
relativeTo: skippedHourDay
}), 12 / 23, "start before skipped hour, end <1 day after: 12 hours = 12/23 days");

assert.sameValue(hours12Neg.total({
unit: "days",
relativeTo: afterSkippedHour
}), -12 / 23, "start after skipped hour, end <1 day before: -12 hours = -12/23 days");

assert.sameValue(hours25.total({
unit: "days",
relativeTo: repeatedHourDay
}), 1, "start before repeated hour, end >1 day after: 25 hours = 1 day");

assert.sameValue(oneDay.total({
unit: "hours",
relativeTo: repeatedHourDay
}), 25, "start before repeated hour, end >1 day after: 1 day = 25 hours");

assert.sameValue(hours25Neg.total({
unit: "days",
relativeTo: afterRepeatedHour
}), -1, "start after repeated hour, end >1 day before: -25 hours = -1 day");

assert.sameValue(oneDayNeg.total({
unit: "hours",
relativeTo: afterRepeatedHour
}), -25, "start after repeated hour, end >1 day before: -1 day = -25 hours");

assert.sameValue(hours12.total({
unit: "days",
relativeTo: repeatedHourDay
}), 12 / 25, "start before repeated hour, end <1 day after: 12 hours = 12/25 days");

assert.sameValue(hours12Neg.total({
unit: "days",
relativeTo: afterRepeatedHourSameDay
}), -12 / 25, "start after repeated hour, end <1 day before: -12 hours = -12/25 days");

assert.sameValue(hours48.total({
unit: "days",
relativeTo: beforeRepeatedHour
}), 49 / 25, "start before repeated hour, end after: 48 hours = 1 24/25 days");
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-temporal.duration.prototype.total
description: Total day length is 24 hours when not affected by DST
features: [Temporal]
---*/

const oneDay = new Temporal.Duration(0, 0, 0, 1);
const hours48 = new Temporal.Duration(0, 0, 0, 0, 48);

assert.sameValue(oneDay.total("hours"), 24, "with no relativeTo, days are 24 hours");
assert.sameValue(hours48.total({ unit: "days" }), 2, "with no relativeTo, 48 hours = 2 days");

const plainRelativeTo = new Temporal.PlainDate(2017, 1, 1);

assert.sameValue(oneDay.total({ unit: "hours", relativeTo: plainRelativeTo }), 24,
"with PlainDate relativeTo, days are 24 hours");
assert.sameValue(hours48.total({ unit: "days", relativeTo: plainRelativeTo }), 2,
"with PlainDate relativeTo, 48 hours = 2 days")

const zonedRelativeTo = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "+04:30");

assert.sameValue(oneDay.total({ unit: "hours", relativeTo: zonedRelativeTo }), 24,
"with ZonedDateTime relativeTo, days are 24 hours if the duration encompasses no DST change");
assert.sameValue(hours48.total({ unit: "days", relativeTo: zonedRelativeTo }), 2,
"with ZonedDateTime relativeTo, 48 hours = 2 days if the duration encompasses no DST change");
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.total
description: Test representative result for all units, with relativeTo
features: [Temporal]
---*/

const duration = new Temporal.Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5);
const plainRelativeTo = new Temporal.PlainDate(2000, 1, 1);
const zonedRelativeTo = new Temporal.ZonedDateTime(63072000_000_000_000n /* = 1972-01-01T00Z */, "UTC");

const dayMilliseconds = 24 * 3600 * 1000;
const fullYears = 5;
const fullMonths = fullYears * 12 + 5 + 1;
const fullDays = 366 + 365 + 365 + 365 + 366 + 31 + 28 + 31 + 30 + 31 + 5 * 7 + 5;
const fullMilliseconds = fullDays * dayMilliseconds + 5 * 3600_000 + 5 * 60_000 + 5000 + 5;
const partialDayMilliseconds = fullMilliseconds - fullDays * dayMilliseconds + 0.005005;
const fractionalDay = partialDayMilliseconds / dayMilliseconds;
const partialYearDays = fullDays - (fullYears * 365 + 2);
const fractionalYear = partialYearDays / 365 + fractionalDay / 365;
const fractionalMonths = (10 /* = 2025-07-11 - 2025-07-01 */ * dayMilliseconds + partialDayMilliseconds) / (31 * dayMilliseconds);
const totalResults = {
years: fullYears + fractionalYear,
months: fullMonths + fractionalMonths,
weeks: Math.floor(fullDays / 7) + (2 + fractionalDay) / 7,
days: fullDays + fractionalDay,
hours: fullDays * 24 + partialDayMilliseconds / 3600000,
minutes: fullDays * 24 * 60 + partialDayMilliseconds / 60000,
seconds: fullDays * 24 * 60 * 60 + partialDayMilliseconds / 1000,
milliseconds: fullMilliseconds + 0.005005,
microseconds: fullMilliseconds * 1000 + 5.005,
nanoseconds: fullMilliseconds * 1000000 + 5005
};
for (const [unit, expected] of Object.entries(totalResults)) {
for (const relativeTo of [plainRelativeTo, zonedRelativeTo]) {
assert.sameValue(
duration.total({ unit, relativeTo }), expected,
`Duration.total results for ${unit} relative to ${relativeTo}`
);
}
}

0 comments on commit e02220b

Please sign in to comment.