Bring existing toString options tests in sync with each other

Of the toString() methods that have options for printing a time with
seconds and fractional seconds, PlainTime seems to have the most
comprehensive set of tests. Bring all the others (Duration, Instant,
PlainDateTime, and ZonedDateTime) in sync with PlainTime, and edit the
PlainTime ones where necessary to include improvements from the others.

Tests:
  - fractionalseconddigits-invalid-string.js: copy and expand on
    PlainTime's more comprehensive set of invalid strings. Add assertion
    message. Fix front matter.
  - fractionalseconddigits-non-integer.js: Fix front matter.
  - fractionalseconddigits-out-of-range.js: make sure infinity is tested.
    Add assertion messages. Fix front matter.
  - fractionalseconddigits-undefined.js: copy PlainTime's more
    comprehensive test with whole minutes, whole seconds, and subseconds.
    Copy PlainTime's test of an empty function object. Add more
    descriptive variable names and assertion messages. Fix front matter.
  - fractionalseconddigits-wrong-type.js: inline and delete TemporalHelper
    used here; it was only good for this test anyway. Improve assertion
    messages.
  - smallestunit-valid-units.js: copy PlainTime's test with a second value
    with zero seconds even. Refactor repetitive tests into a loop. Copy
    the invalid unit "era" from the Instant test. Add assertion messages.
This commit is contained in:
Philip Chimento 2022-04-07 16:54:51 -07:00 committed by Ms2ger
parent 2c880bf5c1
commit b4c0aeda20
30 changed files with 439 additions and 146 deletions

View File

@ -238,39 +238,6 @@ var TemporalHelpers = {
});
},
/*
* checkFractionalSecondDigitsOptionWrongType(temporalObject):
*
* Checks the string-or-number type handling of the fractionalSecondDigits
* option to the various types' toString() methods. temporalObject is an
* instance of the Temporal type under test.
*/
checkFractionalSecondDigitsOptionWrongType(temporalObject) {
// null is not a number, and converts to the string "null", which is an invalid string value
assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: null }), "null");
// Booleans are not numbers, and convert to the strings "true" or "false", which are invalid
assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: true }), "true");
assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: false }), "false");
// Symbols are not numbers and cannot convert to strings
assert.throws(TypeError, () => temporalObject.toString({ fractionalSecondDigits: Symbol() }), "symbol");
// BigInts are not numbers and convert to strings which are invalid
assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: 2n }), "bigint");
// Objects are not numbers and prefer their toString() methods when converting to a string
assert.throws(RangeError, () => temporalObject.toString({ fractionalSecondDigits: {} }), "plain object");
const toStringExpected = temporalObject.toString({ fractionalSecondDigits: 'auto' });
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = temporalObject.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, toStringExpected, "object with toString");
assert.compareArray(actual, expected, "order of operations");
},
/*
* checkPlainDateTimeConversionFastPath(func):
*

View File

@ -16,6 +16,7 @@ features: [Temporal]
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0);
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos"]) {
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits }));
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) {
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits }),
`"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`);
}

View File

@ -16,7 +16,11 @@ features: [Temporal]
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0);
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -Infinity }));
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -1 }));
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 10 }));
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: Infinity }));
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -Infinity }),
"−∞ is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: -1 }),
"1 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 10 }),
"10 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: Infinity }),
"∞ is out of range for fractionalSecondDigits");

View File

@ -16,10 +16,21 @@ info: |
features: [Temporal]
---*/
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0);
const wholeSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7);
const subSeconds = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650);
const explicit = duration.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, "P1Y2M3W4DT5H6M7.98765S", "default fractionalSecondDigits is auto");
const tests = [
[wholeSeconds, "P1Y2M3W4DT5H6M7S"],
[subSeconds, "P1Y2M3W4DT5H6M7.98765S"],
];
const implicit = duration.toString({});
assert.sameValue(implicit, "P1Y2M3W4DT5H6M7.98765S", "default fractionalSecondDigits is auto");
for (const [duration, expected] of tests) {
const explicit = duration.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)");
const implicit = duration.toString({});
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)");
const lambda = duration.toString(() => {});
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)");
}

View File

@ -22,4 +22,26 @@ features: [Temporal]
---*/
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 650, 0);
TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(duration);
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: null }),
"null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: true }),
"true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: false }),
"false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits");
assert.throws(TypeError, () => duration.toString({ fractionalSecondDigits: Symbol() }),
"symbols are not numbers and cannot convert to strings");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: 2n }),
"bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits");
assert.throws(RangeError, () => duration.toString({ fractionalSecondDigits: {} }),
"plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits");
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = duration.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, "P1Y2M3W4DT5H6M7.98765S", "object with toString uses toString return value");
assert.compareArray(actual, expected, "object with toString calls toString and not valueOf");

View File

@ -9,12 +9,37 @@ features: [Temporal]
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321);
assert.sameValue(duration.toString({ smallestUnit: "second" }), "P1Y2M3W4DT5H6M7S");
assert.sameValue(duration.toString({ smallestUnit: "millisecond" }), "P1Y2M3W4DT5H6M7.987S");
assert.sameValue(duration.toString({ smallestUnit: "microsecond" }), "P1Y2M3W4DT5H6M7.987654S");
assert.sameValue(duration.toString({ smallestUnit: "nanosecond" }), "P1Y2M3W4DT5H6M7.987654321S");
function test(instance, expectations, description) {
for (const [smallestUnit, expectedResult] of expectations) {
assert.sameValue(instance.toString({ smallestUnit }), expectedResult,
`${description} with smallestUnit "${smallestUnit}"`);
}
}
test(
duration,
[
["seconds", "P1Y2M3W4DT5H6M7S"],
["milliseconds", "P1Y2M3W4DT5H6M7.987S"],
["microseconds", "P1Y2M3W4DT5H6M7.987654S"],
["nanoseconds", "P1Y2M3W4DT5H6M7.987654321S"],
],
"subseconds toString"
);
test(
new Temporal.Duration(1, 2, 3, 4, 5, 6, 7),
[
["seconds", "P1Y2M3W4DT5H6M7S"],
["milliseconds", "P1Y2M3W4DT5H6M7.000S"],
["microseconds", "P1Y2M3W4DT5H6M7.000000S"],
["nanoseconds", "P1Y2M3W4DT5H6M7.000000000S"],
],
"whole seconds toString"
);
const notValid = [
"era",
"year",
"month",
"week",
@ -24,5 +49,6 @@ const notValid = [
];
notValid.forEach((smallestUnit) => {
assert.throws(RangeError, () => duration.toString({ smallestUnit }), smallestUnit);
assert.throws(RangeError, () => duration.toString({ smallestUnit }),
`"${smallestUnit}" is not a valid unit for the smallestUnit option`);
});

View File

@ -10,10 +10,13 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.instant.prototype.tostring step 6:
6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
6. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const instant = new Temporal.Instant(1_000_000_000_987_650_000n);
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: "other string" }));
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) {
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits }),
`"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`);
}

View File

@ -10,7 +10,7 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.instant.prototype.tostring step 6:
6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
6. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/

View File

@ -10,13 +10,17 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.instant.prototype.tostring step 6:
6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
6. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const instant = new Temporal.Instant(1_000_000_000_987_650_000n);
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -1 }));
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 10 }));
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -Infinity }));
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: Infinity }));
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -Infinity }),
"−∞ is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: -1 }),
"1 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 10 }),
"10 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: Infinity }),
"∞ is out of range for fractionalSecondDigits");

View File

@ -8,18 +8,31 @@ info: |
sec-getoption step 3:
3. If _value_ is *undefined*, return _fallback_.
sec-getstringornumberoption step 2:
2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_).
2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_).
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.instant.prototype.tostring step 6:
6. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
6. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const instant = new Temporal.Instant(1_000_000_000_987_650_000n);
const zeroSeconds = new Temporal.Instant(0n);
const wholeSeconds = new Temporal.Instant(30_000_000_000n);
const subSeconds = new Temporal.Instant(30_123_400_000n);
const explicit = instant.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, "2001-09-09T01:46:40.98765Z", "default fractionalSecondDigits is auto");
const tests = [
[zeroSeconds, "1970-01-01T00:00:00Z"],
[wholeSeconds, "1970-01-01T00:00:30Z"],
[subSeconds, "1970-01-01T00:00:30.1234Z"],
];
const implicit = instant.toString({});
assert.sameValue(implicit, "2001-09-09T01:46:40.98765Z", "default fractionalSecondDigits is auto");
for (const [instant, expected] of tests) {
const explicit = instant.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)");
const implicit = instant.toString({});
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)");
const lambda = instant.toString(() => {});
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)");
}

View File

@ -22,4 +22,26 @@ features: [Temporal]
---*/
const instant = new Temporal.Instant(1_000_000_000_987_650_000n);
TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(instant);
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: null }),
"null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: true }),
"true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: false }),
"false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits");
assert.throws(TypeError, () => instant.toString({ fractionalSecondDigits: Symbol() }),
"symbols are not numbers and cannot convert to strings");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: 2n }),
"bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits");
assert.throws(RangeError, () => instant.toString({ fractionalSecondDigits: {} }),
"plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits");
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = instant.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, "2001-09-09T01:46:40.98765Z", "object with toString uses toString return value");
assert.compareArray(actual, expected, "object with toString calls toString and not valueOf");

View File

@ -9,11 +9,36 @@ features: [Temporal]
const instant = new Temporal.Instant(1_000_000_000_123_456_789n);
assert.sameValue(instant.toString({ smallestUnit: "minute" }), "2001-09-09T01:46Z");
assert.sameValue(instant.toString({ smallestUnit: "second" }), "2001-09-09T01:46:40Z");
assert.sameValue(instant.toString({ smallestUnit: "millisecond" }), "2001-09-09T01:46:40.123Z");
assert.sameValue(instant.toString({ smallestUnit: "microsecond" }), "2001-09-09T01:46:40.123456Z");
assert.sameValue(instant.toString({ smallestUnit: "nanosecond" }), "2001-09-09T01:46:40.123456789Z");
function test(instance, expectations, description) {
for (const [smallestUnit, expectedResult] of expectations) {
assert.sameValue(instance.toString({ smallestUnit }), expectedResult,
`${description} with smallestUnit "${smallestUnit}"`);
}
}
test(
instant,
[
["minute", "2001-09-09T01:46Z"],
["second", "2001-09-09T01:46:40Z"],
["millisecond", "2001-09-09T01:46:40.123Z"],
["microsecond", "2001-09-09T01:46:40.123456Z"],
["nanosecond", "2001-09-09T01:46:40.123456789Z"],
],
"subseconds toString"
);
test(
new Temporal.Instant(999_999_960_000_000_000n),
[
["minute", "2001-09-09T01:46Z"],
["second", "2001-09-09T01:46:00Z"],
["millisecond", "2001-09-09T01:46:00.000Z"],
["microsecond", "2001-09-09T01:46:00.000000Z"],
["nanosecond", "2001-09-09T01:46:00.000000000Z"],
],
"whole minutes toString"
);
const notValid = [
"era",
@ -25,5 +50,6 @@ const notValid = [
];
notValid.forEach((smallestUnit) => {
assert.throws(RangeError, () => instant.toString({ smallestUnit }), smallestUnit);
assert.throws(RangeError, () => instant.toString({ smallestUnit }),
`"${smallestUnit}" is not a valid unit for the smallestUnit option`);
});

View File

@ -10,10 +10,13 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaindatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0);
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: "other string" }));
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) {
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits }),
`"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`);
}

View File

@ -10,7 +10,7 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaindatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/

View File

@ -10,11 +10,17 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaindatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0);
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }));
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }));
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -Infinity }),
"−∞ is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }),
"1 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }),
"10 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: Infinity }),
"∞ is out of range for fractionalSecondDigits");

View File

@ -8,17 +8,31 @@ info: |
sec-getoption step 3:
3. If _value_ is *undefined*, return _fallback_.
sec-getstringornumberoption step 2:
2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_).
2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_).
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaindatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0);
const zeroSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23);
const wholeSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30);
const subSeconds = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 400);
const explicit = datetime.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, "2000-05-02T12:34:56.98765", "default fractionalSecondDigits is auto");
const tests = [
[zeroSeconds, "1976-11-18T15:23:00"],
[wholeSeconds, "1976-11-18T15:23:30"],
[subSeconds, "1976-11-18T15:23:30.1234"],
];
// See options-undefined.js for {}
for (const [datetime, expected] of tests) {
const explicit = datetime.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)");
const implicit = datetime.toString({});
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)");
const lambda = datetime.toString(() => {});
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)");
}

View File

@ -22,4 +22,26 @@ features: [Temporal]
---*/
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 650, 0);
TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(datetime);
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: null }),
"null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: true }),
"true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: false }),
"false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits");
assert.throws(TypeError, () => datetime.toString({ fractionalSecondDigits: Symbol() }),
"symbols are not numbers and cannot convert to strings");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 2n }),
"bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: {} }),
"plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits");
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = datetime.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, "2000-05-02T12:34:56.98765", "object with toString uses toString return value");
assert.compareArray(actual, expected, "object with toString calls toString and not valueOf");

View File

@ -7,15 +7,41 @@ description: Valid units for the smallestUnit option
features: [Temporal]
---*/
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 789, 999, 999);
const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 123, 456, 789);
assert.sameValue(datetime.toString({ smallestUnit: "minute" }), "2000-05-02T12:34");
assert.sameValue(datetime.toString({ smallestUnit: "second" }), "2000-05-02T12:34:56");
assert.sameValue(datetime.toString({ smallestUnit: "millisecond" }), "2000-05-02T12:34:56.789");
assert.sameValue(datetime.toString({ smallestUnit: "microsecond" }), "2000-05-02T12:34:56.789999");
assert.sameValue(datetime.toString({ smallestUnit: "nanosecond" }), "2000-05-02T12:34:56.789999999");
function test(instance, expectations, description) {
for (const [smallestUnit, expectedResult] of expectations) {
assert.sameValue(instance.toString({ smallestUnit }), expectedResult,
`${description} with smallestUnit "${smallestUnit}"`);
}
}
test(
datetime,
[
["minute", "2000-05-02T12:34"],
["second", "2000-05-02T12:34:56"],
["millisecond", "2000-05-02T12:34:56.123"],
["microsecond", "2000-05-02T12:34:56.123456"],
["nanosecond", "2000-05-02T12:34:56.123456789"],
],
"subseconds toString"
);
test(
new Temporal.PlainDateTime(2000, 5, 2, 12, 34),
[
["minute", "2000-05-02T12:34"],
["second", "2000-05-02T12:34:00"],
["millisecond", "2000-05-02T12:34:00.000"],
["microsecond", "2000-05-02T12:34:00.000000"],
["nanosecond", "2000-05-02T12:34:00.000000000"],
],
"whole minutes toString"
);
const notValid = [
"era",
"year",
"month",
"week",
@ -24,5 +50,6 @@ const notValid = [
];
notValid.forEach((smallestUnit) => {
assert.throws(RangeError, () => datetime.toString({ smallestUnit }), smallestUnit);
assert.throws(RangeError, () => datetime.toString({ smallestUnit }),
`"${smallestUnit}" is not a valid unit for the smallestUnit option`);
});

View File

@ -10,12 +10,13 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaintime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0);
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos"]) {
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits }));
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) {
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits }),
`"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`);
}

View File

@ -10,7 +10,7 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaintime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/

View File

@ -10,13 +10,17 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaintime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0);
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -Infinity }));
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -1 }));
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 10 }));
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: Infinity }));
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -Infinity }),
"−∞ is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: -1 }),
"1 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 10 }),
"10 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: Infinity }),
"∞ is out of range for fractionalSecondDigits");

View File

@ -8,29 +8,31 @@ info: |
sec-getoption step 3:
3. If _value_ is *undefined*, return _fallback_.
sec-getstringornumberoption step 2:
2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_).
2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_).
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.plaintime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const zeroSeconds = new Temporal.PlainTime(15, 23);
const wholeSeconds = new Temporal.PlainTime(15, 23, 30);
const subSeconds = new Temporal.PlainTime(15, 23, 30, 123, 400);
const tests = [
["15:23", "15:23:00"],
["15:23:30", "15:23:30"],
["15:23:30.1234", "15:23:30.1234"],
[zeroSeconds, "15:23:00"],
[wholeSeconds, "15:23:30"],
[subSeconds, "15:23:30.1234"],
];
for (const [input, expected] of tests) {
const time = Temporal.PlainTime.from(input);
for (const [time, expected] of tests) {
const explicit = time.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto");
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)");
const implicit = time.toString({});
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto");
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)");
const lambda = time.toString(() => {});
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto");
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)");
}

View File

@ -22,4 +22,26 @@ features: [Temporal]
---*/
const time = new Temporal.PlainTime(12, 34, 56, 987, 650, 0);
TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(time);
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: null }),
"null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: true }),
"true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: false }),
"false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits");
assert.throws(TypeError, () => time.toString({ fractionalSecondDigits: Symbol() }),
"symbols are not numbers and cannot convert to strings");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: 2n }),
"bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits");
assert.throws(RangeError, () => time.toString({ fractionalSecondDigits: {} }),
"plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits");
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = time.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, "12:34:56.98765", "object with toString uses toString return value");
assert.compareArray(actual, expected, "object with toString calls toString and not valueOf");

View File

@ -7,21 +7,41 @@ description: Valid units for the smallestUnit option
features: [Temporal]
---*/
const time = new Temporal.PlainTime(12, 34, 56, 789, 999, 999);
assert.sameValue(time.toString({ smallestUnit: "minute" }), "12:34");
assert.sameValue(time.toString({ smallestUnit: "second" }), "12:34:56");
assert.sameValue(time.toString({ smallestUnit: "millisecond" }), "12:34:56.789");
assert.sameValue(time.toString({ smallestUnit: "microsecond" }), "12:34:56.789999");
assert.sameValue(time.toString({ smallestUnit: "nanosecond" }), "12:34:56.789999999");
const time = new Temporal.PlainTime(12, 34, 56, 123, 456, 789);
const time2 = new Temporal.PlainTime(12, 34);
assert.sameValue(time2.toString({ smallestUnit: "minute" }), "12:34");
assert.sameValue(time2.toString({ smallestUnit: "second" }), "12:34:00");
assert.sameValue(time2.toString({ smallestUnit: "millisecond" }), "12:34:00.000");
assert.sameValue(time2.toString({ smallestUnit: "microsecond" }), "12:34:00.000000");
assert.sameValue(time2.toString({ smallestUnit: "nanosecond" }), "12:34:00.000000000");
function test(instance, expectations, description) {
for (const [smallestUnit, expectedResult] of expectations) {
assert.sameValue(instance.toString({ smallestUnit }), expectedResult,
`${description} with smallestUnit "${smallestUnit}"`);
}
}
test(
time,
[
["minute", "12:34"],
["second", "12:34:56"],
["millisecond", "12:34:56.123"],
["microsecond", "12:34:56.123456"],
["nanosecond", "12:34:56.123456789"],
],
"subseconds toString"
);
test(
new Temporal.PlainTime(12, 34),
[
["minute", "12:34"],
["second", "12:34:00"],
["millisecond", "12:34:00.000"],
["microsecond", "12:34:00.000000"],
["nanosecond", "12:34:00.000000000"],
],
"whole minutes toString"
);
const notValid = [
"era",
"year",
"month",
"week",
@ -30,5 +50,6 @@ const notValid = [
];
notValid.forEach((smallestUnit) => {
assert.throws(RangeError, () => time.toString({ smallestUnit }), smallestUnit);
assert.throws(RangeError, () => time.toString({ smallestUnit }),
`"${smallestUnit}" is not a valid unit for the smallestUnit option`);
});

View File

@ -9,11 +9,14 @@ info: |
4. If _stringValues_ is not *undefined* and _stringValues_ does not contain an element equal to _value_, throw a *RangeError* exception.
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.instant.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
sec-temporal.zoneddatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: "other string" }));
for (const fractionalSecondDigits of ["other string", "AUTO", "not-auto", "autos", "auto\0"]) {
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits }),
`"${fractionalSecondDigits}" is not a valid value for fractionalSecondDigits`);
}

View File

@ -10,7 +10,7 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.zoneddatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/

View File

@ -10,11 +10,17 @@ info: |
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.zoneddatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }));
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }));
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -Infinity }),
"−∞ is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: -1 }),
"1 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 10 }),
"10 is out of range for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: Infinity }),
"∞ is out of range for fractionalSecondDigits");

View File

@ -8,17 +8,31 @@ info: |
sec-getoption step 3:
3. If _value_ is *undefined*, return _fallback_.
sec-getstringornumberoption step 2:
2. Let _value_ be ? GetOption(_options_, _property_, *"stringOrNumber"*, *undefined*, _fallback_).
2. Let _value_ be ? GetOption(_options_, _property_, « Number, String », *undefined*, _fallback_).
sec-temporal-tosecondsstringprecision step 9:
9. Let _digits_ be ? GetStringOrNumberOption(_normalizedOptions_, *"fractionalSecondDigits"*, « *"auto"* », 0, 9, *"auto"*).
sec-temporal.zoneddatetime.prototype.tostring step 4:
4. Let _precision_ be ? ToDurationSecondsStringPrecision(_options_).
4. Let _precision_ be ? ToSecondsStringPrecision(_options_).
features: [Temporal]
---*/
const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC");
const zeroSeconds = new Temporal.ZonedDateTime(0n, "UTC");
const wholeSeconds = new Temporal.ZonedDateTime(30_000_000_000n, "UTC");
const subSeconds = new Temporal.ZonedDateTime(30_123_400_000n, "UTC");
const explicit = datetime.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, "2001-09-09T01:46:40.98765+00:00[UTC]", "default fractionalSecondDigits is auto");
const tests = [
[zeroSeconds, "1970-01-01T00:00:00+00:00[UTC]"],
[wholeSeconds, "1970-01-01T00:00:30+00:00[UTC]"],
[subSeconds, "1970-01-01T00:00:30.1234+00:00[UTC]"],
];
// See options-undefined.js for {}
for (const [datetime, expected] of tests) {
const explicit = datetime.toString({ fractionalSecondDigits: undefined });
assert.sameValue(explicit, expected, "default fractionalSecondDigits is auto (property present but undefined)");
const implicit = datetime.toString({});
assert.sameValue(implicit, expected, "default fractionalSecondDigits is auto (property not present)");
const lambda = datetime.toString(() => {});
assert.sameValue(lambda, expected, "default fractionalSecondDigits is auto (property not present, function object)");
}

View File

@ -22,4 +22,26 @@ features: [Temporal]
---*/
const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_650_000n, "UTC");
TemporalHelpers.checkFractionalSecondDigitsOptionWrongType(datetime);
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: null }),
"null is not a number and converts to the string 'null' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: true }),
"true is not a number and converts to the string 'true' which is not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: false }),
"false is not a number and converts to the string 'false' which is not valid for fractionalSecondDigits");
assert.throws(TypeError, () => datetime.toString({ fractionalSecondDigits: Symbol() }),
"symbols are not numbers and cannot convert to strings");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: 2n }),
"bigints are not numbers and convert to strings which are not valid for fractionalSecondDigits");
assert.throws(RangeError, () => datetime.toString({ fractionalSecondDigits: {} }),
"plain objects are not numbers and convert to strings which are not valid for fractionalSecondDigits");
const expected = [
"get fractionalSecondDigits.toString",
"call fractionalSecondDigits.toString",
];
const actual = [];
const observer = TemporalHelpers.toPrimitiveObserver(actual, "auto", "fractionalSecondDigits");
const result = datetime.toString({ fractionalSecondDigits: observer });
assert.sameValue(result, "2001-09-09T01:46:40.98765+00:00[UTC]", "object with toString uses toString return value");
assert.compareArray(actual, expected, "object with toString calls toString and not valueOf");

View File

@ -9,13 +9,39 @@ features: [Temporal]
const datetime = new Temporal.ZonedDateTime(1_000_000_000_123_456_789n, "UTC");
assert.sameValue(datetime.toString({ smallestUnit: "minute" }), "2001-09-09T01:46+00:00[UTC]");
assert.sameValue(datetime.toString({ smallestUnit: "second" }), "2001-09-09T01:46:40+00:00[UTC]");
assert.sameValue(datetime.toString({ smallestUnit: "millisecond" }), "2001-09-09T01:46:40.123+00:00[UTC]");
assert.sameValue(datetime.toString({ smallestUnit: "microsecond" }), "2001-09-09T01:46:40.123456+00:00[UTC]");
assert.sameValue(datetime.toString({ smallestUnit: "nanosecond" }), "2001-09-09T01:46:40.123456789+00:00[UTC]");
function test(instance, expectations, description) {
for (const [smallestUnit, expectedResult] of expectations) {
assert.sameValue(instance.toString({ smallestUnit }), expectedResult,
`${description} with smallestUnit "${smallestUnit}"`);
}
}
test(
datetime,
[
["minute", "2001-09-09T01:46+00:00[UTC]"],
["second", "2001-09-09T01:46:40+00:00[UTC]"],
["millisecond", "2001-09-09T01:46:40.123+00:00[UTC]"],
["microsecond", "2001-09-09T01:46:40.123456+00:00[UTC]"],
["nanosecond", "2001-09-09T01:46:40.123456789+00:00[UTC]"],
],
"subseconds toString"
);
test(
new Temporal.ZonedDateTime(999_999_960_000_000_000n, "UTC"),
[
["minute", "2001-09-09T01:46+00:00[UTC]"],
["second", "2001-09-09T01:46:00+00:00[UTC]"],
["millisecond", "2001-09-09T01:46:00.000+00:00[UTC]"],
["microsecond", "2001-09-09T01:46:00.000000+00:00[UTC]"],
["nanosecond", "2001-09-09T01:46:00.000000000+00:00[UTC]"],
],
"whole minutes toString"
);
const notValid = [
"era",
"year",
"month",
"week",
@ -24,5 +50,6 @@ const notValid = [
];
notValid.forEach((smallestUnit) => {
assert.throws(RangeError, () => datetime.toString({ smallestUnit }), smallestUnit);
assert.throws(RangeError, () => datetime.toString({ smallestUnit }),
`"${smallestUnit}" is not a valid unit for the smallestUnit option`);
});