From 22e01996f357c5a519baa6e5910ac970b9c13b61 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 1 Nov 2022 16:15:55 -0700 Subject: [PATCH] Temporal: Expand order-of-operations tests to cover different types of relativeTo The `relativeTo` parameter in an options bag may be undefined, a PlainDate instance, or a ZonedDateTime instance. Each of these three possibilities causes a different set of observable operations, which we can test in our existing order-of-operations tests. --- .../Duration/compare/order-of-operations.js | 117 ++++-- .../prototype/add/order-of-operations.js | 208 +++++++++- .../prototype/round/order-of-operations.js | 358 +++++++++++------- .../prototype/subtract/order-of-operations.js | 208 +++++++++- .../prototype/total/order-of-operations.js | 224 +++++++---- 5 files changed, 853 insertions(+), 262 deletions(-) diff --git a/test/built-ins/Temporal/Duration/compare/order-of-operations.js b/test/built-ins/Temporal/Duration/compare/order-of-operations.js index cb50fd405d..589d57249b 100644 --- a/test/built-ins/Temporal/Duration/compare/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/compare/order-of-operations.js @@ -73,6 +73,86 @@ const expected = [ "call two.years.valueOf", // ToRelativeTemporalObject "get options.relativeTo", +]; +const actual = []; + +// basic order of observable operations with no relativeTo +Temporal.Duration.compare( + createDurationPropertyBagObserver("one", 0, 0, 0, 7), + createDurationPropertyBagObserver("two", 0, 0, 0, 6), + createOptionsObserver(undefined) +); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +const expectedOpsForPlainRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.microsecond", + "get options.relativeTo.millisecond", + "get options.relativeTo.minute", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.second", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", +]); + +const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "options.relativeTo"); + +function createOptionsObserver(relativeTo = undefined) { + return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options"); +} + +function createDurationPropertyBagObserver(name, y = 0, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0) { + return TemporalHelpers.propertyBagObserver(actual, { + years: y, + months: mon, + weeks: w, + days: d, + hours: h, + minutes: min, + seconds: s, + milliseconds: ms, + microseconds: µs, + nanoseconds: ns, + }, name); +} + +// order of observable operations with plain relativeTo and without calendar units +Temporal.Duration.compare( + createDurationPropertyBagObserver("one", 0, 0, 0, 7), + createDurationPropertyBagObserver("two", 0, 0, 0, 6), + createOptionsObserver(plainRelativeTo) +); +assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo and no calendar units"); +actual.splice(0); // clear + +const expectedOpsForZonedRelativeTo = expected.concat([ + // ToRelativeTemporalObject "get options.relativeTo.calendar", "has options.relativeTo.calendar.calendar", "get options.relativeTo.calendar.fields", @@ -142,10 +222,9 @@ const expected = [ "call options.relativeTo.timeZone.getPossibleInstantsFor", "get options.relativeTo.timeZone.getOffsetNanosecondsFor", "call options.relativeTo.timeZone.getOffsetNanosecondsFor", -]; -const actual = []; +]); -const relativeTo = TemporalHelpers.propertyBagObserver(actual, { +const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, { year: 2001, month: 5, monthCode: "M05", @@ -161,37 +240,18 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, { timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), }, "options.relativeTo"); -function createOptionsObserver(relativeTo = undefined) { - return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options"); -} - -function createDurationPropertyBagObserver(name, y = 0, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0) { - return TemporalHelpers.propertyBagObserver(actual, { - years: y, - months: mon, - weeks: w, - days: d, - hours: h, - minutes: min, - seconds: s, - milliseconds: ms, - microseconds: µs, - nanoseconds: ns, - }, name); -} - -// basic order of observable operations, without +// order of observable operations with zoned relativeTo and without calendar units Temporal.Duration.compare( createDurationPropertyBagObserver("one", 0, 0, 0, 7), createDurationPropertyBagObserver("two", 0, 0, 0, 6), - createOptionsObserver(relativeTo) + createOptionsObserver(zonedRelativeTo) ); -assert.compareArray(actual, expected, "order of operations"); +assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo and no calendar units"); actual.splice(0, actual.length); // clear // code path through UnbalanceDurationRelative that balances higher units down // to days: -const expectedOpsForDayBalancing = expected.concat([ +const expectedOpsForDayBalancing = expectedOpsForZonedRelativeTo.concat([ // UnbalanceDurationRelative "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 7.a ToTemporalDate "call options.relativeTo.timeZone.getOffsetNanosecondsFor", @@ -210,7 +270,6 @@ const expectedOpsForDayBalancing = expected.concat([ Temporal.Duration.compare( createDurationPropertyBagObserver("one", 1, 1, 1), createDurationPropertyBagObserver("two", 1, 1, 1, 1), - createOptionsObserver(relativeTo) + createOptionsObserver(zonedRelativeTo) ); -assert.compareArray(actual.slice(expected.length), expectedOpsForDayBalancing.slice(expected.length), "order of operations with calendar units"); -actual.splice(0, actual.length); // clear +assert.compareArray(actual, expectedOpsForDayBalancing, "order of operations with calendar units"); diff --git a/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js index 93b3f805dc..235e54942b 100644 --- a/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/add/order-of-operations.js @@ -8,9 +8,8 @@ includes: [compareArray.js, temporalHelpers.js] features: [Temporal] ---*/ -const instance = new Temporal.Duration(1, 2, 0, 4, 5, 6, 7, 987, 654, 321); -const relativeTo = new Temporal.PlainDateTime(2000, 1, 1); const expected = [ + // ToTemporalDurationRecord "get fields.days", "get fields.days.valueOf", "call fields.days.valueOf", @@ -41,8 +40,75 @@ const expected = [ "get fields.years", "get fields.years.valueOf", "call fields.years.valueOf", + // ToRelativeTemporalObject + "get options.relativeTo", ]; const actual = []; + +const simpleFields = TemporalHelpers.propertyBagObserver(actual, { + years: 0, + months: 0, + weeks: 0, + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +function createOptionsObserver(relativeTo = undefined) { + return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options"); +} + +// basic order of observable operations, without any calendar units: +const simpleInstance = new Temporal.Duration(0, 0, 0, 1, 1, 1, 1, 1, 1, 1); +simpleInstance.add(simpleFields, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +const expectedOpsForPlainRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + // PrepareTemporalFields + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.microsecond", + "get options.relativeTo.millisecond", + "get options.relativeTo.minute", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.second", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + // InterpretTemporalDateTimeFields + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + // ToRelativeTemporalObject again + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + // AddDuration + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", +]); + +const instance = new Temporal.Duration(1, 2, 0, 4, 5, 6, 7, 987, 654, 321); + const fields = TemporalHelpers.propertyBagObserver(actual, { years: 1, months: 1, @@ -55,6 +121,138 @@ const fields = TemporalHelpers.propertyBagObserver(actual, { microseconds: 1, nanoseconds: 1, }, "fields"); -const result = instance.add(fields, { relativeTo }); -TemporalHelpers.assertDuration(result, 2, 3, 0, 12, 6, 7, 8, 988, 655, 322); -assert.compareArray(actual, expected, "order of operations"); + +const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 1, + monthCode: "M01", + day: 1, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "options.relativeTo"); + +instance.add(fields, createOptionsObserver(plainRelativeTo)); +assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo"); +actual.splice(0); // clear + +const expectedOpsForZonedRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + // PrepareTemporalFields + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.hour.valueOf", + "call options.relativeTo.hour.valueOf", + "get options.relativeTo.microsecond", + "get options.relativeTo.microsecond.valueOf", + "call options.relativeTo.microsecond.valueOf", + "get options.relativeTo.millisecond", + "get options.relativeTo.millisecond.valueOf", + "call options.relativeTo.millisecond.valueOf", + "get options.relativeTo.minute", + "get options.relativeTo.minute.valueOf", + "call options.relativeTo.minute.valueOf", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.nanosecond.valueOf", + "call options.relativeTo.nanosecond.valueOf", + "get options.relativeTo.second", + "get options.relativeTo.second.valueOf", + "call options.relativeTo.second.valueOf", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + // InterpretTemporalDateTimeFields + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + // ToRelativeTemporalObject again + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + "has options.relativeTo.timeZone.timeZone", + "get options.relativeTo.offset.toString", + "call options.relativeTo.offset.toString", + // InterpretISODateTimeOffset + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → AddZonedDateTime 1 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → AddZonedDateTime 2 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → DifferenceZonedDateTime → DifferenceISODateTime + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", + // AddDuration → DifferenceZonedDateTime → AddZonedDateTime + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", +]); + +const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 1, + monthCode: "M01", + day: 1, + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + offset: "+00:00", + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), +}, "options.relativeTo"); + +instance.add(fields, createOptionsObserver(zonedRelativeTo)); +assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo"); diff --git a/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js index 492ba99d6d..2539537f58 100644 --- a/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js @@ -23,6 +23,199 @@ const expected = [ "call options.roundingIncrement.valueOf", // ToRelativeTemporalObject "get options.relativeTo", +]; +const actual = []; + +function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + smallestUnit, + largestUnit, + roundingMode, + roundingIncrement, + relativeTo, + }, "options"); +} + +const instance = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 2400); + +// basic order of operations, without relativeTo: +instance.round(createOptionsObserver({ smallestUnit: "microseconds" })); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +const expectedOpsForPlainRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.microsecond", + "get options.relativeTo.millisecond", + "get options.relativeTo.minute", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.second", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", +]); + +const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "options.relativeTo"); + +// basic order of observable operations, without rounding: +instance.round(createOptionsObserver({ relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations for PlainDate relativeTo"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expectedOpsForPlainRelativeTo.concat([ + "get options.relativeTo.calendar.dateAdd", // 9.b + "call options.relativeTo.calendar.dateAdd", // 9.c + "call options.relativeTo.calendar.dateAdd", // 9.e + "call options.relativeTo.calendar.dateAdd", // 9.j + "get options.relativeTo.calendar.dateUntil", // 9.m + "call options.relativeTo.calendar.dateUntil", // 9.m + "call options.relativeTo.calendar.dateAdd", // 9.r + "call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.round(createOptionsObserver({ smallestUnit: "years", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through Duration.prototype.round that rounds to the nearest month: +const expectedOpsForMonthRounding = expectedOpsForPlainRelativeTo.concat([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 9.b + "get options.relativeTo.calendar.dateUntil", // 9.c + "call options.relativeTo.calendar.dateAdd", // 9.d.i + "call options.relativeTo.calendar.dateUntil", // 9.d.iv + // RoundDuration + "get options.relativeTo.calendar.dateAdd", // 10.b + "call options.relativeTo.calendar.dateAdd", // 10.c + "call options.relativeTo.calendar.dateAdd", // 10.e + "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate +], Array(2).fill("call options.relativeTo.calendar.dateAdd"), [ // 2× 10.n.iii MoveRelativeDate + // BalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", +]); +const instance2 = new Temporal.Duration(1, 0, 0, 62); +instance2.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "months", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with largestUnit = smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through Duration.prototype.round that rounds to the nearest week: +const expectedOpsForWeekRounding = expectedOpsForPlainRelativeTo.concat([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 10.b + "call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate + // RoundDuration + "get options.relativeTo.calendar.dateAdd", // 11.c + "call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate +], Array(58).fill("call options.relativeTo.calendar.dateAdd"), [ // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2) + // BalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 12.b + "call options.relativeTo.calendar.dateAdd", // 12.c +]); +const instance3 = new Temporal.Duration(1, 1, 0, 15); +instance3.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "weeks", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with largestUnit = smallestUnit = weeks"); +actual.splice(0, actual.length); // clear + +// code path through UnbalanceDurationRelative that rounds to the nearest day: +const expectedOpsForDayRounding = expectedOpsForPlainRelativeTo.concat([ + "get options.relativeTo.calendar.dateAdd", // 11.a.ii + "call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate +]); +const instance4 = new Temporal.Duration(1, 1, 1) +instance4.round(createOptionsObserver({ largestUnit: "days", smallestUnit: "days", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with largestUnit = smallestUnit = days"); +actual.splice(0, actual.length); // clear + +// code path through BalanceDurationRelative balancing from days up to years: +const expectedOpsForDayToYearBalancing = expectedOpsForPlainRelativeTo.concat([ + "get options.relativeTo.calendar.dateAdd", // 10.a + "call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.e.iv MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.i.iv MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.j + "get options.relativeTo.calendar.dateUntil", // 10.k + "call options.relativeTo.calendar.dateUntil", // 10.n +]); +const instance5 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 396 * 24); +instance5.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "days", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForDayToYearBalancing, "order of operations with largestUnit = years, smallestUnit = days"); +actual.splice(0, actual.length); // clear + +// code path through Duration.prototype.round balancing from months up to years: +const expectedOpsForMonthToYearBalancing = expectedOpsForPlainRelativeTo.concat([ + // RoundDuration + "get options.relativeTo.calendar.dateAdd", // 10.b + "call options.relativeTo.calendar.dateAdd", // 10.c + "call options.relativeTo.calendar.dateAdd", // 10.e + "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate + // BalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 10.a + "call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.j + "get options.relativeTo.calendar.dateUntil", // 10.k + "call options.relativeTo.calendar.dateUntil", // 10.n + "call options.relativeTo.calendar.dateAdd", // 10.p.iv + "call options.relativeTo.calendar.dateUntil", // 10.p.vii +]); +const instance6 = new Temporal.Duration(0, 12); +instance6.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "months", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForMonthToYearBalancing, "order of operations with largestUnit = years, smallestUnit = months"); +actual.splice(0, actual.length); // clear + +const expectedOpsForDayToMonthBalancing = expectedOpsForPlainRelativeTo.concat([ + // BalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 11.a + "call options.relativeTo.calendar.dateAdd", // 11.b MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 11.e.iv MoveRelativeDate +]); +const instance7 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 32 * 24); +instance7.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "days", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForDayToMonthBalancing, "order of operations with largestUnit = months, smallestUnit = days"); +actual.splice(0, actual.length); // clear + +const expectedOpsForDayToWeekBalancing = expectedOpsForPlainRelativeTo.concat([ + // BalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 12.b + "call options.relativeTo.calendar.dateAdd", // 12.c MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 12.f.iv MoveRelativeDate +]); +const instance8 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 8 * 24); +instance8.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "days", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForDayToWeekBalancing, "order of operations with largestUnit = weeks, smallestUnit = days"); +actual.splice(0, actual.length); // clear + +const expectedOpsForZonedRelativeTo = expected.concat([ + // ToRelativeTemporalObject "get options.relativeTo.calendar", "has options.relativeTo.calendar.calendar", "get options.relativeTo.calendar.fields", @@ -61,10 +254,20 @@ const expected = [ "call options.relativeTo.calendar.dateFromFields", "get options.relativeTo.offset", "get options.relativeTo.timeZone", -]; -const actual = []; + "has options.relativeTo.timeZone.timeZone", + "get options.relativeTo.offset.toString", + "call options.relativeTo.offset.toString", + // InterpretISODateTimeOffset + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // RoundDuration → ToTemporalDate + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", +]); -const relativeTo = TemporalHelpers.propertyBagObserver(actual, { +const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, { year: 2001, month: 5, monthCode: "M05", @@ -75,150 +278,11 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, { millisecond: 987, microsecond: 654, nanosecond: 321, + offset: "+00:00", calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), }, "options.relativeTo"); -function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) { - return TemporalHelpers.propertyBagObserver(actual, { - smallestUnit, - largestUnit, - roundingMode, - roundingIncrement, - relativeTo, - }, "options"); -} - -const instance = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 2400); - -// basic order of observable operations, without rounding: -instance.round(createOptionsObserver({ relativeTo })); -assert.compareArray(actual, expected, "order of operations"); -actual.splice(0, actual.length); // clear - -// code path through RoundDuration that rounds to the nearest year: -const expectedOpsForYearRounding = expected.concat([ - "get options.relativeTo.calendar.dateAdd", // 9.b - "call options.relativeTo.calendar.dateAdd", // 9.c - "call options.relativeTo.calendar.dateAdd", // 9.e - "call options.relativeTo.calendar.dateAdd", // 9.j - "get options.relativeTo.calendar.dateUntil", // 9.m - "call options.relativeTo.calendar.dateUntil", // 9.m - "call options.relativeTo.calendar.dateAdd", // 9.r - "call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate -]); -instance.round(createOptionsObserver({ smallestUnit: "years", relativeTo })); -assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); -actual.splice(0, actual.length); // clear - -// code path through Duration.prototype.round that rounds to the nearest month: -const expectedOpsForMonthRounding = expected.concat([ - // UnbalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 9.b - "get options.relativeTo.calendar.dateUntil", // 9.c - "call options.relativeTo.calendar.dateAdd", // 9.d.i - "call options.relativeTo.calendar.dateUntil", // 9.d.iv - // RoundDuration - "get options.relativeTo.calendar.dateAdd", // 10.b - "call options.relativeTo.calendar.dateAdd", // 10.c - "call options.relativeTo.calendar.dateAdd", // 10.e - "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate -], Array(2).fill("call options.relativeTo.calendar.dateAdd"), [ // 2× 10.n.iii MoveRelativeDate - // BalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", - "call options.relativeTo.calendar.dateAdd", -]); -const instance2 = new Temporal.Duration(1, 0, 0, 62); -instance2.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "months", relativeTo })); -assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with largestUnit = smallestUnit = months"); -actual.splice(0, actual.length); // clear - -// code path through Duration.prototype.round that rounds to the nearest week: -const expectedOpsForWeekRounding = expected.concat([ - // UnbalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 10.b - "call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate - // RoundDuration - "get options.relativeTo.calendar.dateAdd", // 11.c - "call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate -], Array(58).fill("call options.relativeTo.calendar.dateAdd"), [ // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2) - // BalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 12.b - "call options.relativeTo.calendar.dateAdd", // 12.c -]); -const instance3 = new Temporal.Duration(1, 1, 0, 15); -instance3.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "weeks", relativeTo })); -assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with largestUnit = smallestUnit = weeks"); -actual.splice(0, actual.length); // clear - -// code path through UnbalanceDurationRelative that rounds to the nearest day: -const expectedOpsForDayRounding = expected.concat([ - "get options.relativeTo.calendar.dateAdd", // 11.a.ii - "call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate -]); -const instance4 = new Temporal.Duration(1, 1, 1) -instance4.round(createOptionsObserver({ largestUnit: "days", smallestUnit: "days", relativeTo })); -assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with largestUnit = smallestUnit = days"); -actual.splice(0, actual.length); // clear - -// code path through BalanceDurationRelative balancing from days up to years: -const expectedOpsForDayToYearBalancing = expected.concat([ - "get options.relativeTo.calendar.dateAdd", // 10.a - "call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.e.iv MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.i.iv MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.j - "get options.relativeTo.calendar.dateUntil", // 10.k - "call options.relativeTo.calendar.dateUntil", // 10.n -]); -const instance5 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 396 * 24); -instance5.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "days", relativeTo })); -assert.compareArray(actual, expectedOpsForDayToYearBalancing, "order of operations with largestUnit = years, smallestUnit = days"); -actual.splice(0, actual.length); // clear - -// code path through Duration.prototype.round balancing from months up to years: -const expectedOpsForMonthToYearBalancing = expected.concat([ - // RoundDuration - "get options.relativeTo.calendar.dateAdd", // 10.b - "call options.relativeTo.calendar.dateAdd", // 10.c - "call options.relativeTo.calendar.dateAdd", // 10.e - "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate - // BalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 10.a - "call options.relativeTo.calendar.dateAdd", // 10.b MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.f MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.j - "get options.relativeTo.calendar.dateUntil", // 10.k - "call options.relativeTo.calendar.dateUntil", // 10.n - "call options.relativeTo.calendar.dateAdd", // 10.p.iv - "call options.relativeTo.calendar.dateUntil", // 10.p.vii -]); -const instance6 = new Temporal.Duration(0, 12); -instance6.round(createOptionsObserver({ largestUnit: "years", smallestUnit: "months", relativeTo })); -assert.compareArray(actual, expectedOpsForMonthToYearBalancing, "order of operations with largestUnit = years, smallestUnit = months"); -actual.splice(0, actual.length); // clear - -const expectedOpsForDayToMonthBalancing = expected.concat([ - // BalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 11.a - "call options.relativeTo.calendar.dateAdd", // 11.b MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 11.e.iv MoveRelativeDate -]); -const instance7 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 32 * 24); -instance7.round(createOptionsObserver({ largestUnit: "months", smallestUnit: "days", relativeTo })); -assert.compareArray(actual, expectedOpsForDayToMonthBalancing, "order of operations with largestUnit = months, smallestUnit = days"); -actual.splice(0, actual.length); // clear - -const expectedOpsForDayToWeekBalancing = expected.concat([ - // BalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 12.b - "call options.relativeTo.calendar.dateAdd", // 12.c MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 12.f.iv MoveRelativeDate -]); -const instance8 = new Temporal.Duration(0, 0, 0, 0, /* hours = */ 8 * 24); -instance8.round(createOptionsObserver({ largestUnit: "weeks", smallestUnit: "days", relativeTo })); -assert.compareArray(actual, expectedOpsForDayToWeekBalancing, "order of operations with largestUnit = weeks, smallestUnit = days"); -actual.splice(0, actual.length); // clear +// basic order of operations with ZonedDateTime relativeTo: +instance.round(createOptionsObserver({ relativeTo: zonedRelativeTo })); +assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations for ZonedDateTime relativeTo"); diff --git a/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js index 682d0eacc8..68cc1d3b6b 100644 --- a/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js @@ -8,9 +8,8 @@ includes: [compareArray.js, temporalHelpers.js] features: [Temporal] ---*/ -const instance = new Temporal.Duration(1, 2, 1, 4, 5, 6, 7, 987, 654, 321); -const relativeTo = new Temporal.PlainDateTime(2000, 1, 1); const expected = [ + // ToTemporalDurationRecord "get fields.days", "get fields.days.valueOf", "call fields.days.valueOf", @@ -41,8 +40,75 @@ const expected = [ "get fields.years", "get fields.years.valueOf", "call fields.years.valueOf", + // ToRelativeTemporalObject + "get options.relativeTo", ]; const actual = []; + +const simpleFields = TemporalHelpers.propertyBagObserver(actual, { + years: 0, + months: 0, + weeks: 0, + days: 1, + hours: 1, + minutes: 1, + seconds: 1, + milliseconds: 1, + microseconds: 1, + nanoseconds: 1, +}, "fields"); + +function createOptionsObserver(relativeTo = undefined) { + return TemporalHelpers.propertyBagObserver(actual, { relativeTo }, "options"); +} + +// basic order of observable operations, without any calendar units: +const simpleInstance = new Temporal.Duration(0, 0, 0, 1, 1, 1, 1, 1, 1, 1); +simpleInstance.subtract(simpleFields, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +const expectedOpsForPlainRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + // PrepareTemporalFields + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.microsecond", + "get options.relativeTo.millisecond", + "get options.relativeTo.minute", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.second", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + // InterpretTemporalDateTimeFields + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + // ToRelativeTemporalObject again + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + // AddDuration + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", +]); + +const instance = new Temporal.Duration(1, 2, 1, 4, 5, 6, 7, 987, 654, 321); + const fields = TemporalHelpers.propertyBagObserver(actual, { years: 1, months: 1, @@ -55,6 +121,138 @@ const fields = TemporalHelpers.propertyBagObserver(actual, { microseconds: 1, nanoseconds: 1, }, "fields"); -const result = instance.subtract(fields, { relativeTo }); -TemporalHelpers.assertDuration(result, 0, 1, 0, 3, 4, 5, 6, 986, 653, 320); -assert.compareArray(actual, expected, "order of operations"); + +const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 1, + monthCode: "M01", + day: 1, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "options.relativeTo"); + +instance.subtract(fields, createOptionsObserver(plainRelativeTo)); +assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations with PlainDate relativeTo"); +actual.splice(0); // clear + +const expectedOpsForZonedRelativeTo = expected.concat([ + // ToRelativeTemporalObject + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + // PrepareTemporalFields + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.hour.valueOf", + "call options.relativeTo.hour.valueOf", + "get options.relativeTo.microsecond", + "get options.relativeTo.microsecond.valueOf", + "call options.relativeTo.microsecond.valueOf", + "get options.relativeTo.millisecond", + "get options.relativeTo.millisecond.valueOf", + "call options.relativeTo.millisecond.valueOf", + "get options.relativeTo.minute", + "get options.relativeTo.minute.valueOf", + "call options.relativeTo.minute.valueOf", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.nanosecond.valueOf", + "call options.relativeTo.nanosecond.valueOf", + "get options.relativeTo.second", + "get options.relativeTo.second.valueOf", + "call options.relativeTo.second.valueOf", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + // InterpretTemporalDateTimeFields + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + // ToRelativeTemporalObject again + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + "has options.relativeTo.timeZone.timeZone", + "get options.relativeTo.offset.toString", + "call options.relativeTo.offset.toString", + // InterpretISODateTimeOffset + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → AddZonedDateTime 1 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → AddZonedDateTime 2 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → DifferenceZonedDateTime → DifferenceISODateTime + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", + // AddDuration → DifferenceZonedDateTime → AddZonedDateTime + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → DifferenceISODateTime + "get options.relativeTo.calendar.dateUntil", + "call options.relativeTo.calendar.dateUntil", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 1 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // AddDuration → DifferenceZonedDateTime → NanosecondsToDays → AddZonedDateTime 2 + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "get options.relativeTo.calendar.dateAdd", + "call options.relativeTo.calendar.dateAdd", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", +]); + +const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2000, + month: 1, + monthCode: "M01", + day: 1, + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + offset: "+00:00", + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), +}, "options.relativeTo"); + +instance.subtract(fields, createOptionsObserver(zonedRelativeTo)); +assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations with ZonedDateTime relativeTo"); diff --git a/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js b/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js index 877f10ddb1..cfe1879c48 100644 --- a/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js +++ b/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js @@ -9,6 +9,138 @@ features: [Temporal] ---*/ const expected = [ + "get options.relativeTo", + "get options.unit", + "get options.unit.toString", + "call options.unit.toString", +]; +const actual = []; + +function createOptionsObserver({ unit = "nanoseconds", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + unit, + roundingMode, + roundingIncrement, + relativeTo, + }, "options"); +} + +const instance = new Temporal.Duration(0, 0, 0, 0, 2400); + +// basic order of observable operations, with no relativeTo +instance.total(createOptionsObserver({ unit: "nanoseconds" })); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0); // clear + +const expectedOpsForPlainRelativeTo = [ + // ToRelativeTemporalObject + "get options.relativeTo", + "get options.relativeTo.calendar", + "has options.relativeTo.calendar.calendar", + "get options.relativeTo.calendar.fields", + "call options.relativeTo.calendar.fields", + "get options.relativeTo.day", + "get options.relativeTo.day.valueOf", + "call options.relativeTo.day.valueOf", + "get options.relativeTo.hour", + "get options.relativeTo.microsecond", + "get options.relativeTo.millisecond", + "get options.relativeTo.minute", + "get options.relativeTo.month", + "get options.relativeTo.month.valueOf", + "call options.relativeTo.month.valueOf", + "get options.relativeTo.monthCode", + "get options.relativeTo.monthCode.toString", + "call options.relativeTo.monthCode.toString", + "get options.relativeTo.nanosecond", + "get options.relativeTo.second", + "get options.relativeTo.year", + "get options.relativeTo.year.valueOf", + "call options.relativeTo.year.valueOf", + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + // GetTemporalUnit + "get options.unit", + "get options.unit.toString", + "call options.unit.toString", +]; + +const plainRelativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "options.relativeTo"); + +// basic order of observable operations, without rounding: +instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForPlainRelativeTo, "order of operations for PlainDate relativeTo"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expectedOpsForPlainRelativeTo.concat([ + "get options.relativeTo.calendar.dateAdd", // 9.b + "call options.relativeTo.calendar.dateAdd", // 9.c + "call options.relativeTo.calendar.dateAdd", // 9.e + "call options.relativeTo.calendar.dateAdd", // 9.j + "get options.relativeTo.calendar.dateUntil", // 9.m + "call options.relativeTo.calendar.dateUntil", // 9.m + "call options.relativeTo.calendar.dateAdd", // 9.r + "call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.total(createOptionsObserver({ unit: "years", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with unit = years"); +actual.splice(0, actual.length); // clear + +// code path through Duration.prototype.total that rounds to the nearest month: +const expectedOpsForMonthRounding = expectedOpsForPlainRelativeTo.concat([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 9.b + "get options.relativeTo.calendar.dateUntil", // 9.c + "call options.relativeTo.calendar.dateAdd", // 9.d.i + "call options.relativeTo.calendar.dateUntil", // 9.d.iv + // RoundDuration + "get options.relativeTo.calendar.dateAdd", // 10.b + "call options.relativeTo.calendar.dateAdd", // 10.c + "call options.relativeTo.calendar.dateAdd", // 10.e + "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate +], Array(2).fill("call options.relativeTo.calendar.dateAdd")); // 2× 10.n.iii MoveRelativeDate +const instance2 = new Temporal.Duration(1, 0, 0, 62); +instance2.total(createOptionsObserver({ unit: "months", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with unit = months"); +actual.splice(0, actual.length); // clear + +// code path through Duration.prototype.total that rounds to the nearest week: +const expectedOpsForWeekRounding = expectedOpsForPlainRelativeTo.concat([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 10.b + "call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate + // RoundDuration + "get options.relativeTo.calendar.dateAdd", // 11.c + "call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate +], Array(58).fill("call options.relativeTo.calendar.dateAdd")); // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2) +const instance3 = new Temporal.Duration(1, 1, 0, 15); +instance3.total(createOptionsObserver({ unit: "weeks", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with unit = weeks"); +actual.splice(0, actual.length); // clear + +// code path through UnbalanceDurationRelative that rounds to the nearest day: +const expectedOpsForDayRounding = expectedOpsForPlainRelativeTo.concat([ + "get options.relativeTo.calendar.dateAdd", // 11.a.ii + "call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate + "call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate +]); +const instance4 = new Temporal.Duration(1, 1, 1) +instance4.total(createOptionsObserver({ unit: "days", relativeTo: plainRelativeTo })); +assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with unit = days"); +actual.splice(0, actual.length); // clear + +const expectedOpsForZonedRelativeTo = [ // ToRelativeTemporalObject "get options.relativeTo", "get options.relativeTo.calendar", @@ -49,14 +181,24 @@ const expected = [ "call options.relativeTo.calendar.dateFromFields", "get options.relativeTo.offset", "get options.relativeTo.timeZone", + "has options.relativeTo.timeZone.timeZone", + "get options.relativeTo.offset.toString", + "call options.relativeTo.offset.toString", + // InterpretISODateTimeOffset + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", // GetTemporalUnit "get options.unit", "get options.unit.toString", "call options.unit.toString", + // RoundDuration → ToTemporalDate + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", ]; -const actual = []; -const relativeTo = TemporalHelpers.propertyBagObserver(actual, { +const zonedRelativeTo = TemporalHelpers.propertyBagObserver(actual, { year: 2001, month: 5, monthCode: "M05", @@ -67,81 +209,11 @@ const relativeTo = TemporalHelpers.propertyBagObserver(actual, { millisecond: 987, microsecond: 654, nanosecond: 321, + offset: "+00:00", calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "options.relativeTo.timeZone"), }, "options.relativeTo"); -function createOptionsObserver({ unit = "nanoseconds", roundingMode = "halfExpand", roundingIncrement = 1, relativeTo = undefined } = {}) { - return TemporalHelpers.propertyBagObserver(actual, { - unit, - roundingMode, - roundingIncrement, - relativeTo, - }, "options"); -} - -const instance = new Temporal.Duration(0, 0, 0, 0, 2400); - // basic order of observable operations, without rounding: -instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo })); -assert.compareArray(actual, expected, "order of operations"); -actual.splice(0, actual.length); // clear - -// code path through RoundDuration that rounds to the nearest year: -const expectedOpsForYearRounding = expected.concat([ - "get options.relativeTo.calendar.dateAdd", // 9.b - "call options.relativeTo.calendar.dateAdd", // 9.c - "call options.relativeTo.calendar.dateAdd", // 9.e - "call options.relativeTo.calendar.dateAdd", // 9.j - "get options.relativeTo.calendar.dateUntil", // 9.m - "call options.relativeTo.calendar.dateUntil", // 9.m - "call options.relativeTo.calendar.dateAdd", // 9.r - "call options.relativeTo.calendar.dateAdd", // 9.w MoveRelativeDate -]); -instance.total(createOptionsObserver({ unit: "years", relativeTo })); -assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with unit = years"); -actual.splice(0, actual.length); // clear - -// code path through Duration.prototype.total that rounds to the nearest month: -const expectedOpsForMonthRounding = expected.concat([ - // UnbalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 9.b - "get options.relativeTo.calendar.dateUntil", // 9.c - "call options.relativeTo.calendar.dateAdd", // 9.d.i - "call options.relativeTo.calendar.dateUntil", // 9.d.iv - // RoundDuration - "get options.relativeTo.calendar.dateAdd", // 10.b - "call options.relativeTo.calendar.dateAdd", // 10.c - "call options.relativeTo.calendar.dateAdd", // 10.e - "call options.relativeTo.calendar.dateAdd", // 10.k MoveRelativeDate -], Array(2).fill("call options.relativeTo.calendar.dateAdd")); // 2× 10.n.iii MoveRelativeDate -const instance2 = new Temporal.Duration(1, 0, 0, 62); -instance2.total(createOptionsObserver({ unit: "months", relativeTo })); -assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with unit = months"); -actual.splice(0, actual.length); // clear - -// code path through Duration.prototype.total that rounds to the nearest week: -const expectedOpsForWeekRounding = expected.concat([ - // UnbalanceDurationRelative - "get options.relativeTo.calendar.dateAdd", // 10.b - "call options.relativeTo.calendar.dateAdd", // 10.c.i MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 10.d.i MoveRelativeDate - // RoundDuration - "get options.relativeTo.calendar.dateAdd", // 11.c - "call options.relativeTo.calendar.dateAdd", // 11.d MoveRelativeDate -], Array(58).fill("call options.relativeTo.calendar.dateAdd")); // 58× 11.g.iii MoveRelativeDate (52 + 4 + 2) -const instance3 = new Temporal.Duration(1, 1, 0, 15); -instance3.total(createOptionsObserver({ unit: "weeks", relativeTo })); -assert.compareArray(actual, expectedOpsForWeekRounding, "order of operations with unit = weeks"); -actual.splice(0, actual.length); // clear - -// code path through UnbalanceDurationRelative that rounds to the nearest day: -const expectedOpsForDayRounding = expected.concat([ - "get options.relativeTo.calendar.dateAdd", // 11.a.ii - "call options.relativeTo.calendar.dateAdd", // 11.a.iii.1 MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 11.a.iv.1 MoveRelativeDate - "call options.relativeTo.calendar.dateAdd", // 11.a.v.1 MoveRelativeDate -]); -const instance4 = new Temporal.Duration(1, 1, 1) -instance4.total(createOptionsObserver({ unit: "days", relativeTo })); -assert.compareArray(actual, expectedOpsForDayRounding, "order of operations with unit = days"); -actual.splice(0, actual.length); // clear +instance.total(createOptionsObserver({ unit: "nanoseconds", relativeTo: zonedRelativeTo })); +assert.compareArray(actual, expectedOpsForZonedRelativeTo, "order of operations for ZonedDateTime relativeTo");