Skip to content

Commit

Permalink
Temporal: Add TemporalHelpers.calendarObserver
Browse files Browse the repository at this point in the history
Similar to the previous commits with property bags and time zones, there
are also some existing tests that use a Proxy to test the order of
observable operations which involve user code
passed in as part of a Temporal.TimeZone object. I am going to write
several more tests that do this, as well. This seems like a good thing to
put into TemporalHelpers, where it can be implemented consistently so that
we don't get discrepancies in which operations are tracked, or bugs due to
a Symbol-valued property.

Updates existing tests to use this helper.
  • Loading branch information
ptomato authored and Ms2ger committed Oct 5, 2022
1 parent 12f919e commit ae52931
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 62 deletions.
91 changes: 91 additions & 0 deletions harness/temporalHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,97 @@ var TemporalHelpers = {
});
},

/*
* calendarObserver:
* A custom calendar that behaves exactly like the ISO 8601 calendar but
* tracks calls to any of its methods, and Get/Has operations on its
* properties, by appending messages to an array. This is for the purpose of
* testing order of operations that are observable from user code.
* objectName is used in the log.
*/
calendarObserver(calls, objectName, methodOverrides = {}) {
const iso8601 = new Temporal.Calendar("iso8601");
const trackingMethods = {
dateFromFields(...args) {
calls.push(`call ${objectName}.dateFromFields`);
if ('dateFromFields' in methodOverrides) {
const value = methodOverrides.dateFromFields;
return typeof value === "function" ? value(...args) : value;
}
const originalResult = iso8601.dateFromFields(...args);
// Replace the calendar in the result with the call-tracking calendar
const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
const result = new Temporal.PlainDate(isoYear, isoMonth, isoDay, this);
// Remove the HasProperty check resulting from the above constructor call
assert.sameValue(calls.pop(), `has ${objectName}.calendar`);
return result;
},
yearMonthFromFields(...args) {
calls.push(`call ${objectName}.yearMonthFromFields`);
if ('yearMonthFromFields' in methodOverrides) {
const value = methodOverrides.yearMonthFromFields;
return typeof value === "function" ? value(...args) : value;
}
const originalResult = iso8601.yearMonthFromFields(...args);
// Replace the calendar in the result with the call-tracking calendar
const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
const result = new Temporal.PlainYearMonth(isoYear, isoMonth, this, isoDay);
// Remove the HasProperty check resulting from the above constructor call
assert.sameValue(calls.pop(), `has ${objectName}.calendar`);
return result;
},
monthDayFromFields(...args) {
calls.push(`call ${objectName}.monthDayFromFields`);
if ('monthDayFromFields' in methodOverrides) {
const value = methodOverrides.monthDayFromFields;
return typeof value === "function" ? value(...args) : value;
}
const originalResult = iso8601.monthDayFromFields(...args);
// Replace the calendar in the result with the call-tracking calendar
const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
const result = new Temporal.PlainMonthDay(isoMonth, isoDay, this, isoYear);
// Remove the HasProperty check resulting from the above constructor call
assert.sameValue(calls.pop(), `has ${objectName}.calendar`);
return result;
},
dateAdd(...args) {
calls.push(`call ${objectName}.dateAdd`);
if ('dateAdd' in methodOverrides) {
const value = methodOverrides.dateAdd;
return typeof value === "function" ? value(...args) : value;
}
const originalResult = iso8601.dateAdd(...args);
const {isoYear, isoMonth, isoDay} = originalResult.getISOFields();
const result = new Temporal.PlainDate(isoYear, isoMonth, isoDay, this);
// Remove the HasProperty check resulting from the above constructor call
assert.sameValue(calls.pop(), `has ${objectName}.calendar`);
return result;
}
};
// Automatically generate the other methods that don't need any custom code
["toString", "dateUntil", "era", "eraYear", "year", "month", "monthCode", "day", "fields", "mergeFields"].forEach((methodName) => {
trackingMethods[methodName] = function (...args) {
actual.push(`call ${formatPropertyName(methodName, objectName)}`);
if (methodName in methodOverrides) {
const value = methodOverrides[methodName];
return typeof value === "function" ? value(...args) : value;
}
return iso8601[methodName](...args);
};
});
return new Proxy(trackingMethods, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
actual.push(`get ${formatPropertyName(key, objectName)}`);
return result;
},
has(target, key) {
actual.push(`has ${formatPropertyName(key, objectName)}`);
return Reflect.has(target, key);
},
});
},

/*
* A custom calendar that does not allow any of its methods to be called, for
* the purpose of asserting that a particular operation does not call into
Expand Down
38 changes: 7 additions & 31 deletions test/built-ins/Temporal/Now/plainDateTime/calendar-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/*---
esid: sec-temporal.now.plaindatetime
description: Observable interactions with the provided calendar-like object
includes: [compareArray.js]
includes: [compareArray.js, temporalHelpers.js]
features: [Proxy, Temporal]
---*/

Expand All @@ -18,41 +18,17 @@ const expectedWith = [
'has calendar.calendar',
'get calendar.calendar',
'has nestedCalendar.calendar',
'get nestedCalendar.Symbol(Symbol.toPrimitive)',
'get nestedCalendar[Symbol.toPrimitive]',
'get nestedCalendar.toString',
'call nestedCalendar.toString'
];
const nestedCalendar = new Proxy({
toString: function() {
actual.push('call nestedCalendar.toString');
return 'iso8601';
}
}, {
has(target, property) {
actual.push(`has nestedCalendar.${String(property)}`);
return property in target;
},
get(target, property) {
actual.push(`get nestedCalendar.${String(property)}`);
return target[property];
},
const nestedCalendar = TemporalHelpers.calendarObserver(actual, "nestedCalendar", {
toString: "iso8601",
});
const calendar = new Proxy({
calendar: nestedCalendar,
toString: function() {
actual.push('call calendar.toString');
return 'iso8601';
},
}, {
has(target, property) {
actual.push(`has calendar.${String(property)}`);
return property in target;
},
get(target, property) {
actual.push(`get calendar.${String(property)}`);
return target[property];
},
const calendar = TemporalHelpers.calendarObserver(actual, "calendar", {
toString: "iso8601",
});
calendar.calendar = nestedCalendar;

Object.defineProperty(Temporal.Calendar, 'from', {
get() {
Expand Down
38 changes: 7 additions & 31 deletions test/built-ins/Temporal/Now/zonedDateTime/calendar-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/*---
esid: sec-temporal.now.zoneddatetime
description: Observable interactions with the provided calendar-like object
includes: [compareArray.js]
includes: [compareArray.js, temporalHelpers.js]
features: [Proxy, Temporal]
---*/

Expand All @@ -18,41 +18,17 @@ const expectedWith = [
'has calendar.calendar',
'get calendar.calendar',
'has nestedCalendar.calendar',
'get nestedCalendar.Symbol(Symbol.toPrimitive)',
'get nestedCalendar[Symbol.toPrimitive]',
'get nestedCalendar.toString',
'call nestedCalendar.toString'
];
const nestedCalendar = new Proxy({
toString: function() {
actual.push('call nestedCalendar.toString');
return 'iso8601';
}
}, {
has(target, property) {
actual.push(`has nestedCalendar.${String(property)}`);
return property in target;
},
get(target, property) {
actual.push(`get nestedCalendar.${String(property)}`);
return target[property];
},
const nestedCalendar = TemporalHelpers.calendarObserver(actual, "nestedCalendar", {
toString: "iso8601",
});
const calendar = new Proxy({
calendar: nestedCalendar,
toString: function() {
actual.push('call calendar.toString');
return 'iso8601';
},
}, {
has(target, property) {
actual.push(`has calendar.${String(property)}`);
return property in target;
},
get(target, property) {
actual.push(`get calendar.${String(property)}`);
return target[property];
},
const calendar = TemporalHelpers.calendarObserver(actual, "calendar", {
toString: "iso8601",
});
calendar.calendar = nestedCalendar;

Object.defineProperty(Temporal.Calendar, 'from', {
get() {
Expand Down

0 comments on commit ae52931

Please sign in to comment.