From b4c0aeda2023fa178a46af0b49dd4a501153820b Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Thu, 7 Apr 2022 16:54:51 -0700 Subject: [PATCH] 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. --- harness/temporalHelpers.js | 33 ------------- .../fractionalseconddigits-invalid-string.js | 5 +- .../fractionalseconddigits-out-of-range.js | 12 +++-- .../fractionalseconddigits-undefined.js | 21 +++++++-- .../fractionalseconddigits-wrong-type.js | 24 +++++++++- .../toString/smallestunit-valid-units.js | 36 ++++++++++++-- .../fractionalseconddigits-invalid-string.js | 7 ++- .../fractionalseconddigits-non-integer.js | 2 +- .../fractionalseconddigits-out-of-range.js | 14 ++++-- .../fractionalseconddigits-undefined.js | 27 ++++++++--- .../fractionalseconddigits-wrong-type.js | 24 +++++++++- .../toString/smallestunit-valid-units.js | 38 ++++++++++++--- .../fractionalseconddigits-invalid-string.js | 7 ++- .../fractionalseconddigits-non-integer.js | 2 +- .../fractionalseconddigits-out-of-range.js | 12 +++-- .../fractionalseconddigits-undefined.js | 26 +++++++--- .../fractionalseconddigits-wrong-type.js | 24 +++++++++- .../toString/smallestunit-valid-units.js | 41 +++++++++++++--- .../fractionalseconddigits-invalid-string.js | 7 +-- .../fractionalseconddigits-non-integer.js | 2 +- .../fractionalseconddigits-out-of-range.js | 14 ++++-- .../fractionalseconddigits-undefined.js | 24 +++++----- .../fractionalseconddigits-wrong-type.js | 24 +++++++++- .../toString/smallestunit-valid-units.js | 47 ++++++++++++++----- .../fractionalseconddigits-invalid-string.js | 9 ++-- .../fractionalseconddigits-non-integer.js | 2 +- .../fractionalseconddigits-out-of-range.js | 12 +++-- .../fractionalseconddigits-undefined.js | 26 +++++++--- .../fractionalseconddigits-wrong-type.js | 24 +++++++++- .../toString/smallestunit-valid-units.js | 39 ++++++++++++--- 30 files changed, 439 insertions(+), 146 deletions(-) diff --git a/harness/temporalHelpers.js b/harness/temporalHelpers.js index c6f190fb263..c9b7645b7f1 100644 --- a/harness/temporalHelpers.js +++ b/harness/temporalHelpers.js @@ -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): * diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js index 036b977ad16..5af9938e232 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-invalid-string.js @@ -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`); } diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js index 9a20541c19f..ab73ad69bd1 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-out-of-range.js @@ -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"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js index 2c3af23ae92..292b8df300a 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-undefined.js @@ -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)"); +} diff --git a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js index 143de7c3440..625daaff1da 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-wrong-type.js @@ -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"); diff --git a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js index fce836b31b1..24880177e23 100644 --- a/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/Duration/prototype/toString/smallestunit-valid-units.js @@ -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`); }); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js index f75db5a7ffc..0a1cc3e3cb8 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string.js @@ -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`); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js index beb567b6889..1a3479b5cc6 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer.js @@ -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] ---*/ diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js index 4506d3ef215..a634aee8903 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range.js @@ -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"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js index 7bed467685f..be0fbf77e38 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined.js @@ -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)"); +} diff --git a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js index 26eb23a3037..419b4a86d16 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type.js @@ -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"); diff --git a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js index 191eec97ed4..e1c53c93eb6 100644 --- a/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units.js @@ -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`); }); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js index 150d868658a..9fa496c2955 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -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`); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js index 7de58c30b34..281d78f1abd 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -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] ---*/ diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js index 948d707eb35..2ccbafaeec0 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -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"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js index 12a0f77b873..d5ebb9c7e68 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-undefined.js @@ -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)"); +} diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js index 9177b82196a..5ecaf7a6d1f 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -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"); diff --git a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js index 34928a9c6d9..6aff7a613b2 100644 --- a/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/PlainDateTime/prototype/toString/smallestunit-valid-units.js @@ -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`); }); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js index 3d4ab17c430..1be21d324c7 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -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`); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js index 9b7c5250e0d..3ca8fed5aa0 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -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] ---*/ diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js index 5959dd94591..1d6e899312f 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -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"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js index 1d9d2dff038..6c33c55f7f4 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-undefined.js @@ -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)"); } diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js index 54440155aa3..79fcd282938 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -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"); diff --git a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js index e2b4c71dbd2..bb942179e2c 100644 --- a/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/PlainTime/prototype/toString/smallestunit-valid-units.js @@ -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`); }); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js index ea172ceb80e..c933354b9d4 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-invalid-string.js @@ -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`); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js index 93685aedece..a9ccce61d8d 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-non-integer.js @@ -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] ---*/ diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js index 36ae8d14293..487600a4158 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-out-of-range.js @@ -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"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js index a4e0a10b5f0..734f436c4c3 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-undefined.js @@ -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)"); +} diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js index b147dbac3e2..9a12691ad6d 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/fractionalseconddigits-wrong-type.js @@ -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"); diff --git a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js index 12c10368b64..6ea787955a9 100644 --- a/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js +++ b/test/built-ins/Temporal/ZonedDateTime/prototype/toString/smallestunit-valid-units.js @@ -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`); });