diff --git a/test/built-ins/Temporal/Duration/compare/order-of-operations.js b/test/built-ins/Temporal/Duration/compare/order-of-operations.js new file mode 100644 index 00000000000..fc029b30a34 --- /dev/null +++ b/test/built-ins/Temporal/Duration/compare/order-of-operations.js @@ -0,0 +1,211 @@ +// 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.duration.compare +description: Properties on objects passed to compare() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDuration on first argument + "get one.days", + "get one.days.valueOf", + "call one.days.valueOf", + "get one.hours", + "get one.hours.valueOf", + "call one.hours.valueOf", + "get one.microseconds", + "get one.microseconds.valueOf", + "call one.microseconds.valueOf", + "get one.milliseconds", + "get one.milliseconds.valueOf", + "call one.milliseconds.valueOf", + "get one.minutes", + "get one.minutes.valueOf", + "call one.minutes.valueOf", + "get one.months", + "get one.months.valueOf", + "call one.months.valueOf", + "get one.nanoseconds", + "get one.nanoseconds.valueOf", + "call one.nanoseconds.valueOf", + "get one.seconds", + "get one.seconds.valueOf", + "call one.seconds.valueOf", + "get one.weeks", + "get one.weeks.valueOf", + "call one.weeks.valueOf", + "get one.years", + "get one.years.valueOf", + "call one.years.valueOf", + // ToTemporalDuration on second argument + "get two.days", + "get two.days.valueOf", + "call two.days.valueOf", + "get two.hours", + "get two.hours.valueOf", + "call two.hours.valueOf", + "get two.microseconds", + "get two.microseconds.valueOf", + "call two.microseconds.valueOf", + "get two.milliseconds", + "get two.milliseconds.valueOf", + "call two.milliseconds.valueOf", + "get two.minutes", + "get two.minutes.valueOf", + "call two.minutes.valueOf", + "get two.months", + "get two.months.valueOf", + "call two.months.valueOf", + "get two.nanoseconds", + "get two.nanoseconds.valueOf", + "call two.nanoseconds.valueOf", + "get two.seconds", + "get two.seconds.valueOf", + "call two.seconds.valueOf", + "get two.weeks", + "get two.weeks.valueOf", + "call two.weeks.valueOf", + "get two.years", + "get two.years.valueOf", + "call two.years.valueOf", + // 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.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", + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", + "has options.relativeTo.timeZone.timeZone", + "get options.relativeTo.timeZone.getPossibleInstantsFor", + "call options.relativeTo.timeZone.getPossibleInstantsFor", + // CalculateOffsetShift on first argument + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // ...in 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", + // ...done with AddZonedDateTime + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + // CalculateOffsetShift on second argument + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "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", + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", +]; +const actual = []; + +const relativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 6, + minute: 54, + second: 32, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), + 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 +Temporal.Duration.compare( + createDurationPropertyBagObserver("one", 0, 0, 0, 7), + createDurationPropertyBagObserver("two", 0, 0, 0, 6), + createOptionsObserver(relativeTo) +); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0, actual.length); // clear + +// code path through UnbalanceDurationRelative that balances higher units down +// to days: +const expectedOpsForDayBalancing = expected.concat([ + // UnbalanceDurationRelative + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 7.a ToTemporalDate + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "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 + // UnbalanceDurationRelative again for the second argument: + "get options.relativeTo.timeZone.getOffsetNanosecondsFor", // 7.a ToTemporalDate + "call options.relativeTo.timeZone.getOffsetNanosecondsFor", + "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 +]); +Temporal.Duration.compare( + createDurationPropertyBagObserver("one", 1, 1, 1), + createDurationPropertyBagObserver("two", 1, 1, 1, 1), + createOptionsObserver(relativeTo) +); +assert.compareArray(actual.slice(expected.length), expectedOpsForDayBalancing.slice(expected.length), "order of operations with calendar units"); +actual.splice(0, actual.length); // clear 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 new file mode 100644 index 00000000000..e859518d1fa --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/round/order-of-operations.js @@ -0,0 +1,229 @@ +// 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.duration.prototype.round +description: Properties on objects passed to round() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // 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.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", + "get options.relativeTo.calendar.dateFromFields", + "call options.relativeTo.calendar.dateFromFields", + "get options.relativeTo.offset", + "get options.relativeTo.timeZone", +]; +const actual = []; + +const relativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 6, + minute: 54, + second: 32, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "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([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 9.b + "get options.relativeTo.calendar.dateUntil", // 9.c + // 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([ + // UnbalanceDurationRelative + "get options.relativeTo.calendar.dateAdd", // 10.b + // 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 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 new file mode 100644 index 00000000000..877f10ddb1b --- /dev/null +++ b/test/built-ins/Temporal/Duration/prototype/total/order-of-operations.js @@ -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.duration.prototype.total +description: Properties on objects passed to total() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // 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.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", + "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 actual = []; + +const relativeTo = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 6, + minute: 54, + second: 32, + millisecond: 987, + microsecond: 654, + nanosecond: 321, + calendar: TemporalHelpers.calendarObserver(actual, "options.relativeTo.calendar"), +}, "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 diff --git a/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js new file mode 100644 index 00000000000..f46668f342e --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js @@ -0,0 +1,128 @@ +// 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.plaindate.prototype.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDate + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); + +const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: 'M05', + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "days", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.since(otherDatePropertyBag, createOptionsObserver()); +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 this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.since(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js new file mode 100644 index 00000000000..3eda54a42b7 --- /dev/null +++ b/test/built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js @@ -0,0 +1,128 @@ +// 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.plaindate.prototype.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDate + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDate(2000, 5, 2, ownCalendar); + +const otherDatePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "days", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.until(otherDatePropertyBag, createOptionsObserver()); +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 this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.until(otherDatePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js new file mode 100644 index 00000000000..d5677432779 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js @@ -0,0 +1,152 @@ +// 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.plaindatetime.prototype.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDateTime + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.since(otherDateTimePropertyBag, createOptionsObserver()); +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 this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js new file mode 100644 index 00000000000..55af95484a3 --- /dev/null +++ b/test/built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js @@ -0,0 +1,152 @@ +// 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.plaindatetime.prototype.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalDateTime + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.until(otherDateTimePropertyBag, createOptionsObserver()); +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 this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat([ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js b/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js new file mode 100644 index 00000000000..59ef87d7c77 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js @@ -0,0 +1,125 @@ +// 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.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalYearMonth + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.yearMonthFromFields", + "call other.calendar.yearMonthFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // CalendarFields / PrepareTemporalFields / CalendarDateFromFields + "get this.calendar.fields", + "call this.calendar.fields", + "get other.calendar.monthCode", + "call other.calendar.monthCode", + "get other.calendar.year", + "call other.calendar.year", + "get this.calendar.dateFromFields", + "call this.calendar.dateFromFields", + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + "get this.calendar.dateFromFields", + "call this.calendar.dateFromFields", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); + +const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "months", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + "get this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.since(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 2 })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js b/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js new file mode 100644 index 00000000000..07b4e4e3184 --- /dev/null +++ b/test/built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js @@ -0,0 +1,125 @@ +// 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.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalYearMonth + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.calendar.yearMonthFromFields", + "call other.calendar.yearMonthFromFields", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", + // CalendarFields / PrepareTemporalFields / CalendarDateFromFields + "get this.calendar.fields", + "call this.calendar.fields", + "get other.calendar.monthCode", + "call other.calendar.monthCode", + "get other.calendar.year", + "call other.calendar.year", + "get this.calendar.dateFromFields", + "call this.calendar.dateFromFields", + "get this.calendar.monthCode", + "call this.calendar.monthCode", + "get this.calendar.year", + "call this.calendar.year", + "get this.calendar.dateFromFields", + "call this.calendar.dateFromFields", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // CalendarDateUntil + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", +]; +const actual = []; + +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.PlainYearMonth(2000, 5, ownCalendar, 1); + +const otherYearMonthPropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "months", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat([ + "get this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.until(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat([ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.until(otherYearMonthPropertyBag, createOptionsObserver({ smallestUnit: "months", roundingIncrement: 2 })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js b/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js new file mode 100644 index 00000000000..618e129848c --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js @@ -0,0 +1,229 @@ +// 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.zoneddatetime.prototype.since +description: Properties on objects passed to since() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalZonedDateTime + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.timeZone", + "get other.offset", + "has other.timeZone.timeZone", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + "get other.timeZone.getPossibleInstantsFor", + "call other.timeZone.getPossibleInstantsFor", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", +]; +const actual = []; + +const ownTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone"); +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, ownTimeZone, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "other.timeZone"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.since(otherDateTimePropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0, actual.length); // clear + +// Making largestUnit a calendar unit adds the following observable operations: +const expectedOpsForCalendarDifference = [ + // TimeZoneEquals + "get this.timeZone[Symbol.toPrimitive]", + "get this.timeZone.toString", + "call this.timeZone.toString", + "get other.timeZone[Symbol.toPrimitive]", + "get other.timeZone.toString", + "call other.timeZone.toString", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // DifferenceZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays → DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // NanosecondsToDays → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // BalanceDuration → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // RoundDuration → ToTemporalDate + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // RoundDuration → MoveRelativeZonedDateTime → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // RoundDuration → NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // RoundDuration → NanosecondsToDays → DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // RoundDuration → NanosecondsToDays → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", +]; + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.since(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js b/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js new file mode 100644 index 00000000000..ea5f2e797f6 --- /dev/null +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js @@ -0,0 +1,229 @@ +// 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.zoneddatetime.prototype.until +description: Properties on objects passed to until() are accessed in the correct order +includes: [compareArray.js, temporalHelpers.js] +features: [Temporal] +---*/ + +const expected = [ + // ToTemporalZonedDateTime + "get other.calendar", + "has other.calendar.calendar", + "get other.calendar.fields", + "call other.calendar.fields", + "get other.day", + "get other.day.valueOf", + "call other.day.valueOf", + "get other.hour", + "get other.hour.valueOf", + "call other.hour.valueOf", + "get other.microsecond", + "get other.microsecond.valueOf", + "call other.microsecond.valueOf", + "get other.millisecond", + "get other.millisecond.valueOf", + "call other.millisecond.valueOf", + "get other.minute", + "get other.minute.valueOf", + "call other.minute.valueOf", + "get other.month", + "get other.month.valueOf", + "call other.month.valueOf", + "get other.monthCode", + "get other.monthCode.toString", + "call other.monthCode.toString", + "get other.nanosecond", + "get other.nanosecond.valueOf", + "call other.nanosecond.valueOf", + "get other.second", + "get other.second.valueOf", + "call other.second.valueOf", + "get other.year", + "get other.year.valueOf", + "call other.year.valueOf", + "get other.timeZone", + "get other.offset", + "has other.timeZone.timeZone", + "get other.calendar.dateFromFields", + "call other.calendar.dateFromFields", + "get other.timeZone.getPossibleInstantsFor", + "call other.timeZone.getPossibleInstantsFor", + // CalendarEquals + "get this.calendar[Symbol.toPrimitive]", + "get this.calendar.toString", + "call this.calendar.toString", + "get other.calendar[Symbol.toPrimitive]", + "get other.calendar.toString", + "call other.calendar.toString", + // GetDifferenceSettings + "get options.smallestUnit", + "get options.smallestUnit.toString", + "call options.smallestUnit.toString", + "get options.largestUnit", + "get options.largestUnit.toString", + "call options.largestUnit.toString", + "get options.roundingMode", + "get options.roundingMode.toString", + "call options.roundingMode.toString", + "get options.roundingIncrement", + "get options.roundingIncrement.valueOf", + "call options.roundingIncrement.valueOf", +]; +const actual = []; + +const ownTimeZone = TemporalHelpers.timeZoneObserver(actual, "this.timeZone"); +const ownCalendar = TemporalHelpers.calendarObserver(actual, "this.calendar"); +const instance = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, ownTimeZone, ownCalendar); + +const otherDateTimePropertyBag = TemporalHelpers.propertyBagObserver(actual, { + year: 2001, + month: 5, + monthCode: "M05", + day: 2, + hour: 1, + minute: 46, + second: 40, + millisecond: 250, + microsecond: 500, + nanosecond: 750, + calendar: TemporalHelpers.calendarObserver(actual, "other.calendar"), + timeZone: TemporalHelpers.timeZoneObserver(actual, "other.timeZone"), +}, "other"); + +function createOptionsObserver({ smallestUnit = "nanoseconds", largestUnit = "auto", roundingMode = "halfExpand", roundingIncrement = 1 } = {}) { + return TemporalHelpers.propertyBagObserver(actual, { + // order is significant, due to iterating through properties in order to + // copy them to an internal null-prototype object: + roundingIncrement, + roundingMode, + largestUnit, + smallestUnit, + additional: "property", + }, "options"); +} + +// clear any observable things that happened while constructing the objects +actual.splice(0, actual.length); + +// basic order of observable operations, without rounding: +instance.until(otherDateTimePropertyBag, createOptionsObserver()); +assert.compareArray(actual, expected, "order of operations"); +actual.splice(0, actual.length); // clear + +// Making largestUnit a calendar unit adds the following observable operations: +const expectedOpsForCalendarDifference = [ + // TimeZoneEquals + "get this.timeZone[Symbol.toPrimitive]", + "get this.timeZone.toString", + "call this.timeZone.toString", + "get other.timeZone[Symbol.toPrimitive]", + "get other.timeZone.toString", + "call other.timeZone.toString", + // MergeLargestUnitOption + "ownKeys options", + "get options.roundingIncrement", + "get options.roundingMode", + "get options.largestUnit", + "get options.smallestUnit", + "get options.additional", + // DifferenceZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // NanosecondsToDays → DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // NanosecondsToDays → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // BalanceDuration → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // RoundDuration → ToTemporalDate + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // RoundDuration → MoveRelativeZonedDateTime → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", + // RoundDuration → NanosecondsToDays + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + // RoundDuration → NanosecondsToDays → DifferenceISODateTime + "get this.calendar.dateUntil", + "call this.calendar.dateUntil", + // RoundDuration → NanosecondsToDays → AddZonedDateTime + "get this.timeZone.getOffsetNanosecondsFor", + "call this.timeZone.getOffsetNanosecondsFor", + "get this.calendar.dateAdd", + "call this.calendar.dateAdd", + "get this.timeZone.getPossibleInstantsFor", + "call this.timeZone.getPossibleInstantsFor", +]; + +// code path through RoundDuration that rounds to the nearest year: +const expectedOpsForYearRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 9.b + "call this.calendar.dateAdd", // 9.c + "call this.calendar.dateAdd", // 9.e + "call this.calendar.dateAdd", // 9.j + "get this.calendar.dateUntil", // 9.m + "call this.calendar.dateUntil", // 9.m + "call this.calendar.dateAdd", // 9.r + "call this.calendar.dateAdd", // 9.w MoveRelativeDate +]); +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "years" })); +assert.compareArray(actual, expectedOpsForYearRounding, "order of operations with smallestUnit = years"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest month: +const expectedOpsForMonthRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 10.b + "call this.calendar.dateAdd", // 10.c + "call this.calendar.dateAdd", // 10.e + "call this.calendar.dateAdd", // 10.k MoveRelativeDate +]); // (10.n.iii MoveRelativeDate not called because weeks == 0) +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "months" })); +assert.compareArray(actual, expectedOpsForMonthRounding, "order of operations with smallestUnit = months"); +actual.splice(0, actual.length); // clear + +// code path through RoundDuration that rounds to the nearest week: +const expectedOpsForWeekRounding = expected.concat(expectedOpsForCalendarDifference, [ + "get this.calendar.dateAdd", // 11.c + "call this.calendar.dateAdd", // 11.d MoveRelativeDate +]); // (11.g.iii MoveRelativeDate not called because days already balanced) +instance.until(otherDateTimePropertyBag, createOptionsObserver({ smallestUnit: "weeks" })); +assert.compareArray(actual.slice(expected.length), expectedOpsForWeekRounding.slice(expected.length), "order of operations with smallestUnit = weeks"); +actual.slice(0, actual.length); // clear