From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../test262/intl402/DateTimeFormat/browser.js | 0 .../test262/intl402/DateTimeFormat/builtin.js | 21 + .../casing-numbering-system-calendar-options.js | 46 ++ .../constructor-calendar-numberingSystem-order.js | 51 ++ .../DateTimeFormat/constructor-default-value.js | 25 + .../constructor-invalid-offset-timezone.js | 38 ++ .../DateTimeFormat/constructor-no-instanceof.js | 25 + .../constructor-options-calendar-invalid.js | 42 ++ .../constructor-options-dateStyle-invalid.js | 31 + .../constructor-options-dateStyle-valid.js | 39 ++ .../constructor-options-dayPeriod-invalid.js | 30 + .../constructor-options-dayPeriod-valid.js | 36 ++ ...uctor-options-fractionalSecondDigits-invalid.js | 39 ++ ...tructor-options-fractionalSecondDigits-valid.js | 44 ++ ...structor-options-invalid-explicit-components.js | 51 ++ .../constructor-options-numberingSystem-invalid.js | 41 ++ .../constructor-options-order-dayPeriod.js | 52 ++ ...tructor-options-order-fractionalSecondDigits.js | 68 +++ .../constructor-options-order-timedate-style.js | 127 ++++ .../DateTimeFormat/constructor-options-order.js | 111 ++++ .../constructor-options-style-conflict.js | 47 ++ ...nstructor-options-throwing-getters-dayPeriod.js | 26 + ...ions-throwing-getters-fractionalSecondDigits.js | 26 + ...ctor-options-throwing-getters-timedate-style.js | 31 + .../constructor-options-throwing-getters.js | 33 ++ .../constructor-options-timeStyle-invalid.js | 31 + .../constructor-options-timeStyle-valid.js | 38 ++ .../constructor-options-timeZoneName-invalid.js | 30 + .../constructor-options-timeZoneName-valid.js | 30 + .../DateTimeFormat/constructor-options-toobject.js | 40 ++ .../intl402/DateTimeFormat/date-time-options.js | 106 ++++ .../default-options-object-prototype.js | 22 + .../ignore-invalid-unicode-ext-values.js | 39 ++ .../instance-proto-and-extensible.js | 19 + .../intl-legacy-constructed-symbol-on-unwrap.js | 34 ++ .../intl-legacy-constructed-symbol.js | 20 + .../legacy-regexp-statics-not-modified.js | 21 + .../tests/test262/intl402/DateTimeFormat/length.js | 34 ++ .../tests/test262/intl402/DateTimeFormat/name.js | 29 + .../numbering-system-calendar-options.js | 69 +++ .../test262/intl402/DateTimeFormat/prop-desc.js | 33 ++ .../DateTimeFormat/proto-from-ctor-realm.js | 60 ++ .../intl402/DateTimeFormat/prototype/browser.js | 0 .../intl402/DateTimeFormat/prototype/builtin.js | 18 + .../prototype/constructor/browser.js | 0 .../prototype/constructor/prop-desc.js | 33 ++ .../DateTimeFormat/prototype/constructor/shell.js | 0 .../DateTimeFormat/prototype/constructor/value.js | 14 + .../format/bound-to-datetimeformat-instance.js | 30 + .../DateTimeFormat/prototype/format/browser.js | 0 .../DateTimeFormat/prototype/format/builtin.js | 33 ++ .../format/date-constructor-not-called.js | 38 ++ .../prototype/format/dayPeriod-long-en.js | 95 +++ .../prototype/format/dayPeriod-narrow-en.js | 95 +++ .../prototype/format/dayPeriod-short-en.js | 95 +++ .../prototype/format/format-function-builtin.js | 33 ++ .../prototype/format/format-function-length.js | 31 + .../prototype/format/format-function-name.js | 28 + .../format/format-function-property-order.js | 18 + .../prototype/format/fractionalSecondDigits.js | 34 ++ .../DateTimeFormat/prototype/format/length.js | 36 ++ .../DateTimeFormat/prototype/format/name.js | 31 + .../prototype/format/no-instanceof.js | 25 + .../prototype/format/offset-timezone-gmt-same.js | 29 + .../format/proleptic-gregorian-calendar.js | 33 ++ .../DateTimeFormat/prototype/format/prop-desc.js | 39 ++ .../prototype/format/related-year-zh.js | 20 + .../DateTimeFormat/prototype/format/shell.js | 55 ++ .../prototype/format/taint-Object-prototype.js | 18 + .../format/temporal-objects-resolved-time-zone.js | 52 ++ .../format/temporal-zoneddatetime-not-supported.js | 20 + .../prototype/format/throws-value-non-finite.js | 20 + .../format/time-clip-near-time-boundaries.js | 39 ++ .../prototype/format/time-clip-to-integer.js | 39 ++ .../prototype/format/timedatestyle-en.js | 114 ++++ .../prototype/formatRange/argument-date-string.js | 41 ++ .../formatRange/argument-near-time-boundaries.js | 49 ++ .../prototype/formatRange/argument-to-integer.js | 41 ++ .../formatRange/argument-tonumber-throws.js | 56 ++ .../prototype/formatRange/browser.js | 0 .../prototype/formatRange/builtin.js | 32 ++ .../formatRange/date-is-infinity-throws.js | 72 +++ .../prototype/formatRange/date-is-nan-throws.js | 49 ++ .../formatRange/date-same-returns-single-date.js | 63 ++ .../prototype/formatRange/date-undefined-throws.js | 44 ++ .../date-x-greater-than-y-not-throws.js | 35 ++ .../DateTimeFormat/prototype/formatRange/en-US.js | 45 ++ .../formatRange/fractionalSecondDigits.js | 42 ++ .../DateTimeFormat/prototype/formatRange/length.js | 16 + .../DateTimeFormat/prototype/formatRange/name.js | 16 + .../prototype/formatRange/prop-desc.js | 23 + .../DateTimeFormat/prototype/formatRange/shell.js | 55 ++ .../temporal-objects-resolved-time-zone.js | 58 ++ .../temporal-zoneddatetime-not-supported.js | 21 + .../prototype/formatRange/this-bad-object.js | 28 + .../formatRange/this-is-not-object-throws.js | 49 ++ .../formatRangeToParts/argument-date-string.js | 41 ++ .../argument-near-time-boundaries.js | 49 ++ .../formatRangeToParts/argument-to-integer.js | 56 ++ .../formatRangeToParts/argument-tonumber-throws.js | 56 ++ .../prototype/formatRangeToParts/browser.js | 0 .../prototype/formatRangeToParts/builtin.js | 32 ++ .../formatRangeToParts/date-is-infinity-throws.js | 71 +++ .../formatRangeToParts/date-is-nan-throws.js | 49 ++ .../date-same-returns-single-date.js | 78 +++ .../formatRangeToParts/date-undefined-throws.js | 43 ++ .../date-x-greater-than-y-not-throws.js | 33 ++ .../prototype/formatRangeToParts/en-US.js | 208 +++++++ .../formatRangeToParts/fractionalSecondDigits.js | 160 ++++++ .../prototype/formatRangeToParts/length.js | 16 + .../prototype/formatRangeToParts/name.js | 16 + .../formatRangeToParts/pattern-on-calendar.js | 40 ++ .../prototype/formatRangeToParts/prop-desc.js | 23 + .../prototype/formatRangeToParts/shell.js | 384 +++++++++++++ .../temporal-objects-resolved-time-zone.js | 117 ++++ .../temporal-zoneddatetime-not-supported.js | 21 + .../formatRangeToParts/this-bad-object.js | 28 + .../this-is-not-object-throws.js | 49 ++ .../prototype/formatToParts/browser.js | 0 .../formatToParts/date-constructor-not-called.js | 38 ++ .../formatToParts/date-is-infinity-throws.js | 35 ++ .../prototype/formatToParts/date-is-nan-throws.js | 35 ++ .../prototype/formatToParts/dayPeriod-long-en.js | 108 ++++ .../prototype/formatToParts/dayPeriod-narrow-en.js | 108 ++++ .../prototype/formatToParts/dayPeriod-short-en.js | 108 ++++ .../prototype/formatToParts/formatToParts.js | 21 + .../formatToParts/fractionalSecondDigits.js | 69 +++ .../prototype/formatToParts/length.js | 15 + .../DateTimeFormat/prototype/formatToParts/main.js | 76 +++ .../DateTimeFormat/prototype/formatToParts/name.js | 15 + .../formatToParts/offset-timezone-correct.js | 30 + .../prototype/formatToParts/pattern-on-calendar.js | 38 ++ .../prototype/formatToParts/related-year-zh.js | 35 ++ .../prototype/formatToParts/related-year.js | 23 + .../formatToParts/return-abrupt-tonumber-date.js | 44 ++ .../prototype/formatToParts/shell.js | 360 ++++++++++++ .../temporal-objects-resolved-time-zone.js | 107 ++++ .../temporal-zoneddatetime-not-supported.js | 20 + .../formatToParts/this-has-not-internal-throws.js | 19 + .../formatToParts/this-is-not-object-throws.js | 40 ++ .../time-clip-near-time-boundaries.js | 39 ++ .../formatToParts/time-clip-to-integer.js | 43 ++ .../intl402/DateTimeFormat/prototype/prop-desc.js | 19 + .../prototype/resolvedOptions/basic.js | 53 ++ .../prototype/resolvedOptions/browser.js | 0 .../prototype/resolvedOptions/builtin.js | 30 + .../resolvedOptions/hourCycle-dateStyle.js | 93 +++ .../prototype/resolvedOptions/hourCycle-default.js | 47 ++ .../resolvedOptions/hourCycle-timeStyle.js | 89 +++ .../prototype/resolvedOptions/hourCycle.js | 102 ++++ .../prototype/resolvedOptions/length.js | 34 ++ .../prototype/resolvedOptions/name.js | 29 + .../prototype/resolvedOptions/no-instanceof.js | 25 + .../resolvedOptions/offset-timezone-basic.js | 30 + .../resolvedOptions/offset-timezone-change.js | 35 ++ .../prototype/resolvedOptions/order-dayPeriod.js | 38 ++ .../order-fractionalSecondDigits.js | 36 ++ .../prototype/resolvedOptions/order-style.js | 42 ++ .../prototype/resolvedOptions/order.js | 50 ++ .../prototype/resolvedOptions/prop-desc.js | 33 ++ .../resolved-locale-with-hc-unicode.js | 88 +++ .../prototype/resolvedOptions/shell.js | 24 + .../intl402/DateTimeFormat/prototype/shell.js | 0 .../this-value-datetimeformat-prototype.js | 17 + .../prototype/this-value-not-datetimeformat.js | 28 + .../prototype/toStringTag/browser.js | 0 .../DateTimeFormat/prototype/toStringTag/shell.js | 0 .../prototype/toStringTag/toString-changed-tag.js | 30 + .../prototype/toStringTag/toString-removed-tag.js | 24 + .../prototype/toStringTag/toString.js | 26 + .../prototype/toStringTag/toStringTag.js | 25 + .../DateTimeFormat/required-date-time-formats.js | 48 ++ .../tests/test262/intl402/DateTimeFormat/shell.js | 0 .../test262/intl402/DateTimeFormat/subclassing.js | 30 + .../DateTimeFormat/supportedLocalesOf/basic.js | 25 + .../DateTimeFormat/supportedLocalesOf/browser.js | 0 .../DateTimeFormat/supportedLocalesOf/builtin.js | 30 + .../DateTimeFormat/supportedLocalesOf/length.js | 34 ++ .../DateTimeFormat/supportedLocalesOf/name.js | 29 + .../DateTimeFormat/supportedLocalesOf/prop-desc.js | 33 ++ .../DateTimeFormat/supportedLocalesOf/shell.js | 24 + .../supportedLocalesOf/taint-Object-prototype.js | 16 + .../taint-Object-prototype-date-time-components.js | 18 + .../taint-Object-prototype-dayPeriod.js | 18 + ...aint-Object-prototype-fractionalSecondDigits.js | 18 + .../DateTimeFormat/taint-Object-prototype.js | 18 + .../test-option-date-time-components.js | 17 + .../DateTimeFormat/test-option-formatMatcher.js | 13 + .../intl402/DateTimeFormat/test-option-hour12.js | 16 + .../DateTimeFormat/test-option-localeMatcher.js | 13 + .../intl402/DateTimeFormat/this-value-ignored.js | 37 ++ .../DateTimeFormat/timezone-case-insensitive.js | 638 +++++++++++++++++++++ .../intl402/DateTimeFormat/timezone-invalid.js | 28 + .../DateTimeFormat/timezone-not-canonicalized.js | 30 + .../test262/intl402/DateTimeFormat/timezone-utc.js | 21 + 195 files changed, 8932 insertions(+) create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/subclassing.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js create mode 100644 js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js (limited to 'js/src/tests/test262/intl402/DateTimeFormat') diff --git a/js/src/tests/test262/intl402/DateTimeFormat/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/builtin.js new file mode 100644 index 0000000000..abffae0582 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/builtin.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.1_L15 +description: > + Tests that Intl.DateTimeFormat meets the requirements for + built-in objects defined by the introduction of chapter 17 of the + ECMAScript Language Specification. +author: Norbert Lindenberg +---*/ + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(Intl.DateTimeFormat), "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat), Function.prototype); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js b/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js new file mode 100644 index 0000000000..15ae3a5e14 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js @@ -0,0 +1,46 @@ +// Copyright 2020 Google Inc, Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that the options numberingSystem and calendar are mapped + to lower case properly. +author: Caio Lima +features: [Array.prototype.includes] +---*/ + +let defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale; + +let supportedNumberingSystems = ["latn", "arab"].filter(nu => + new Intl.DateTimeFormat(defaultLocale + "-u-nu-" + nu) + .resolvedOptions().numberingSystem === nu +); + +if (supportedNumberingSystems.includes("latn")) { + let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-nu-lATn"); + assert.sameValue(dateTimeFormat.resolvedOptions().numberingSystem, "latn", "Numbering system option should be in lower case"); +} + +if (supportedNumberingSystems.includes("arab")) { + let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-nu-Arab"); + assert.sameValue(dateTimeFormat.resolvedOptions().numberingSystem, "arab", "Numbering system option should be in lower case"); +} + +let supportedCalendars = ["gregory", "chinese"].filter(ca => + new Intl.DateTimeFormat(defaultLocale + "-u-ca-" + ca) + .resolvedOptions().calendar === ca +); + +if (supportedCalendars.includes("gregory")) { + let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-ca-Gregory"); + assert.sameValue(dateTimeFormat.resolvedOptions().calendar, "gregory", "Calendar option should be in lower case"); +} + +if (supportedCalendars.includes("chinese")) { + let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-ca-CHINESE"); + assert.sameValue(dateTimeFormat.resolvedOptions().calendar, "chinese", "Calendar option should be in lower case"); +} + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js new file mode 100644 index 0000000000..f7cecd54e7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js @@ -0,0 +1,51 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks the order of getting "calendar" and "numberingSystem" options in the + DateTimeFormat is between "localeMatcher" and "hour12" options. +info: | + 5. Let _matcher_ be ? GetOption(_options_, `"localeMatcher"`, ~string~, « `"lookup"`, `"best fit"` », `"best fit"`). + ... + 7. Let _calendar_ be ? GetOption(_options_, `"calendar"`, ~string~ , ~empty~, *undefined*). + ... + 10. Let _numberingSystem_ be ? GetOption(_options_, `"numberingSystem"`, ~string~, ~empty~, *undefined*). + ... + 13. Let _hour12_ be ? GetOption(_options_, `"hour12"`, ~boolean~, ~empty~, *undefined*). +includes: [compareArray.js] +---*/ + +const actual = []; + +const options = { + get localeMatcher() { + actual.push("localeMatcher"); + return undefined; + }, + get calendar() { + actual.push("calendar"); + return undefined; + }, + get numberingSystem() { + actual.push("numberingSystem"); + return undefined; + }, + get hour12() { + actual.push("hour12"); + return undefined; + }, +}; + +const expected = [ + "localeMatcher", + "calendar", + "numberingSystem", + "hour12" +]; + +let df = new Intl.DateTimeFormat(undefined, options); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js new file mode 100644 index 0000000000..2cfcab904e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js @@ -0,0 +1,25 @@ +// Copyright (C) 2018 Ujjwal Sharma. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that the constructor for Intl.DateTimeFormat uses appropriate default + values for its arguments (locales and options). +---*/ + +const actual = new Intl.DateTimeFormat().resolvedOptions(); +const expected = new Intl.DateTimeFormat( + [], + Object.create(null) +).resolvedOptions(); + +assert.sameValue(actual.locale, expected.locale); +assert.sameValue(actual.calendar, expected.calendar); +assert.sameValue(actual.day, expected.day); +assert.sameValue(actual.month, expected.month); +assert.sameValue(actual.year, expected.year); +assert.sameValue(actual.numberingSystem, expected.numberingSystem); +assert.sameValue(actual.timeZone, expected.timeZone); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js new file mode 100644 index 0000000000..d999f188a8 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js @@ -0,0 +1,38 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: Tests that invalid offset time zones are rejected. +---*/ +let invalidOffsetTimeZones = [ + '+3', + '+24', + '+23:0', + '+130', + '+13234', + '+135678', + '-7', + '-10.50', + '-10,50', + '-24', + '-014', + '-210', + '-2400', + '-1:10', + '-21:0', + '+0:003', + '+15:59:00', + '+15:59.50', + '+15:59,50', + '+222700', + '-02:3200', + '-170100', + '-22230', +]; +invalidOffsetTimeZones.forEach((timeZone) => { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat(undefined, {timeZone}); + }, timeZone + ":"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js new file mode 100644 index 0000000000..c2905aa57b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl-datetimeformat-constructor +description: > + Tests that the Intl.DateTimeFormat constructor calls + OrdinaryHasInstance instead of the instanceof operator which includes a + Symbol.hasInstance lookup and call among other things. +info: > + ChainDateTimeFormat ( dateTimeFormat, newTarget, this ) + 1. If newTarget is undefined and ? OrdinaryHasInstance(%DateTimeFormat%, this) is true, then + a. Perform ? DefinePropertyOrThrow(this, %Intl%.[[FallbackSymbol]], PropertyDescriptor{ + [[Value]]: dateTimeFormat, [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: false }). + b. Return this. +---*/ + +Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, { + get() { throw new Test262Error(); } +}); + +Intl.DateTimeFormat(); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js new file mode 100644 index 0000000000..894392f62c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js @@ -0,0 +1,42 @@ +// Copyright 2020 André Bargull; Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... + 8. If calendar is not undefined, then + a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. +---*/ + +/* + alphanum = (ALPHA / DIGIT) ; letters and numbers + numberingSystem = (3*8alphanum) *("-" (3*8alphanum)) +*/ +const invalidCalendarOptions = [ + "", + "a", + "ab", + "abcdefghi", + "abc-abcdefghi", + "!invalid!", + "-gregory-", + "gregory-", + "gregory--", + "gregory-nu", + "gregory-nu-", + "gregory-nu-latn", + "gregoryé", + "gregory역법", +]; +for (const calendar of invalidCalendarOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat('en', {calendar}); + }, `new Intl.DateTimeFormat("en", {calendar: "${calendar}"}) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js new file mode 100644 index 0000000000..0aac3d9863 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js @@ -0,0 +1,31 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... + 39. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined). +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + + +const invalidOptions = [ + "", + "FULL", + " long", + "short ", + "narrow", + "numeric", +]; +for (const dateStyle of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat("en", { dateStyle }); + }, `new Intl.DateTimeFormat("en", { dateStyle: "${dateStyle}" }) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js new file mode 100644 index 0000000000..0f6dc77f22 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js @@ -0,0 +1,39 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks handling of the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... + 39. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined). + 40. If dateStyle is not undefined, set dateTimeFormat.[[DateStyle]] to dateStyle. +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + + +const validOptions = [ + [undefined, undefined], + ["full", "full"], + ["long", "long"], + ["medium", "medium"], + ["short", "short"], + [{ toString() { return "full"; } }, "full"], + [{ valueOf() { return "long"; }, toString: undefined }, "long"], +]; +for (const [dateStyle, expected] of validOptions) { + const dtf = new Intl.DateTimeFormat("en", { dateStyle }); + const options = dtf.resolvedOptions(); + assert.sameValue(options.dateStyle, expected); + const propdesc = Object.getOwnPropertyDescriptor(options, "dateStyle"); + if (expected === undefined) { + assert.sameValue(propdesc, undefined); + } else { + assert.sameValue(propdesc.value, expected); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js new file mode 100644 index 0000000000..f331b357d7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js @@ -0,0 +1,30 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + [[DayPeriod]] `"dayPeriod"` `"narrow"`, `"short"`, `"long"` + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const invalidOptions = [ + "", + "LONG", + " long", + "short ", + "full", + "numeric", +]; +for (const dayPeriod of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat("en", { dayPeriod }); + }, `new Intl.DateTimeFormat("en", { dayPeriod: "${dayPeriod}" }) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js new file mode 100644 index 0000000000..75acac41a1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js @@ -0,0 +1,36 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks handling of the options argument to the DateTimeFormat constructor. +info: | + [[DayPeriod]] `"dayPeriod"` `"narrow"`, `"short"`, `"long"` + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const validOptions = [ + [undefined, undefined], + ["long", "long"], + ["short", "short"], + ["narrow", "narrow"], + [{ toString() { return "narrow"; } }, "narrow"], + [{ valueOf() { return "long"; }, toString: undefined }, "long"], +]; +for (const [dayPeriod, expected] of validOptions) { + const dtf = new Intl.DateTimeFormat("en", { dayPeriod }); + const options = dtf.resolvedOptions(); + assert.sameValue(options.dayPeriod, expected); + const propdesc = Object.getOwnPropertyDescriptor(options, "dayPeriod"); + if (expected === undefined) { + assert.sameValue(propdesc, undefined); + } else { + assert.sameValue(propdesc.value, expected); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js new file mode 100644 index 0000000000..cd9bc0a97f --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js @@ -0,0 +1,39 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + ... + 37. For each row of Table 7, except the header row, in table order, do + a. Let prop be the name given in the Property column of the row. + b. If prop is "fractionalSecondDigits", then + i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + + +const invalidOptions = [ + "LONG", + " long", + "short ", + "full", + "numeric", + -1, + 4, + "4", + "-1", + -0.00001, + 3.000001, +]; +for (const fractionalSecondDigits of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat("en", { fractionalSecondDigits }); + }, + `new Intl.DateTimeFormat("en", { fractionalSecondDigits: "${fractionalSecondDigits}" }) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js new file mode 100644 index 0000000000..d66e4209cd --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js @@ -0,0 +1,44 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks handling of the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + ... + 37. For each row of Table 7, except the header row, in table order, do + a. Let prop be the name given in the Property column of the row. + b. If prop is "fractionalSecondDigits", then + i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + + +const validOptions = [ + [undefined, undefined], + [1, 1], + ["1", 1], + [2, 2], + ["2", 2], + [3, 3], + ["3", 3], + [2.9, 2], + ["2.9", 2], + [1.00001, 1], + [{ toString() { return "3"; } }, 3], +]; +for (const [fractionalSecondDigits, expected] of validOptions) { + const dtf = new Intl.DateTimeFormat("en", { fractionalSecondDigits }); + const options = dtf.resolvedOptions(); + assert.sameValue(options.fractionalSecondDigits, expected); + const propdesc = Object.getOwnPropertyDescriptor(options, "fractionalSecondDigits"); + if (expected === undefined) { + assert.sameValue(propdesc, undefined); + } else { + assert.sameValue(propdesc.value, expected); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js new file mode 100644 index 0000000000..c435c211bd --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js @@ -0,0 +1,51 @@ +// Copyright 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Verifies that constructor throws when dateStyle is combined with explicit format components. +info: | + CreateDateTimeFormat ( newTarget, locales, options, required, defaults ) + ... + 39. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined). + 40. Set dateTimeFormat.[[DateStyle]] to dateStyle. + 41. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). + 42. Set dateTimeFormat.[[TimeStyle]] to timeStyle. + 43. If dateStyle is not undefined or timeStyle is not undefined, then + + a. If hasExplicitFormatComponents is true, then + i. Throw a TypeError exception. +---*/ + +function optionsThrow(options, testName) { + assert.throws(TypeError, function() { + new Intl.DateTimeFormat(undefined, options); + }, testName + ":"); +} + +optionsThrow({dateStyle: "full", weekday: "long"}, "dateStyle-weekday"); +optionsThrow({dateStyle: "full", era: "long"}, "dateStyle-era"); +optionsThrow({dateStyle: "full", year: "numeric"}, "dateStyle-year"); +optionsThrow({dateStyle: "full", month: "numeric"}, "dateStyle-month"); +optionsThrow({dateStyle: "full", day: "numeric"}, "dateStyle-day"); +optionsThrow({dateStyle: "full", dayPeriod: "long"}, "dateStyle-dayPeriod"); +optionsThrow({dateStyle: "full", hour: "numeric"}, "dateStyle-hour"); +optionsThrow({dateStyle: "full", minute: "numeric"}, "dateStyle-minute"); +optionsThrow({dateStyle: "full", second: "numeric"}, "dateStyle-second"); +optionsThrow({dateStyle: "full", fractionalSecondDigits: 1}, "dateStyle-fractionalSecondDigits"); +optionsThrow({dateStyle: "full", timeZoneName: "short"}, "dateStyle-timeZoneName"); + +optionsThrow({timeStyle: "full", weekday: "long"}, "timeStyle-weekday"); +optionsThrow({timeStyle: "full", era: "long"}, "timeStyle-era"); +optionsThrow({timeStyle: "full", year: "numeric"}, "timeStyle-year"); +optionsThrow({timeStyle: "full", month: "numeric"}, "timeStyle-month"); +optionsThrow({timeStyle: "full", day: "numeric"}, "timeStyle-day"); +optionsThrow({timeStyle: "full", dayPeriod: "long"}, "timeStyle-dayPeriod"); +optionsThrow({timeStyle: "full", hour: "numeric"}, "timeStyle-hour"); +optionsThrow({timeStyle: "full", minute: "numeric"}, "timeStyle-minute"); +optionsThrow({timeStyle: "full", second: "numeric"}, "timeStyle-second"); +optionsThrow({timeStyle: "full", fractionalSecondDigits: 1}, "timeStyle-fractionalSecondDigits"); +optionsThrow({timeStyle: "full", timeZoneName: "short"}, "timeStyle-timeZoneName"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js new file mode 100644 index 0000000000..c1b555c87e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js @@ -0,0 +1,41 @@ +// Copyright 2020 André Bargull; Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + ... + 27. If numberingSystem is not undefined, then + a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. +---*/ + +/* + alphanum = (ALPHA / DIGIT) ; letters and numbers + numberingSystem = (3*8alphanum) *("-" (3*8alphanum)) +*/ +const invalidNumberingSystemOptions = [ + "", + "a", + "ab", + "abcdefghi", + "abc-abcdefghi", + "!invalid!", + "-latn-", + "latn-", + "latn--", + "latn-ca", + "latn-ca-", + "latn-ca-gregory", + "latné", + "latn编号", +]; +for (const numberingSystem of invalidNumberingSystemOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat('en', {numberingSystem}); + }, `new Intl.DateTimeFormat("en", {numberingSystem: "${numberingSystem}"}) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js new file mode 100644 index 0000000000..c05bd1bee8 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js @@ -0,0 +1,52 @@ +// Copyright 2019 Googe Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the order of getting options of 'dayPeriod' for the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( newTarget, locales, options, required, defaults ) + ... + 36. For each row of Table 7, except the header row, in table order, do + a. Let prop be the name given in the Property column of the row. + b. If prop is "fractionalSecondDigits", then + i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). + c. Else, + i. Let values be a List whose elements are the strings given in the Values column of the row. + ii. Let value be ? GetOption(options, prop, string, values, undefined). + d. Set formatOptions.[[]] to value. + ... +includes: [compareArray.js] +features: [Intl.DateTimeFormat-dayPeriod] + +---*/ + +// Just need to ensure dayPeriod are get between day and hour. +const expected = [ + // CreateDateTimeFormat step 36. + "day", + "dayPeriod", + "hour" +]; + +const actual = []; + +const options = { + get day() { + actual.push("day"); + return "numeric"; + }, + get dayPeriod() { + actual.push("dayPeriod"); + return "long"; + }, + get hour() { + actual.push("hour"); + return "numeric"; + }, +}; + +new Intl.DateTimeFormat("en", options); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js new file mode 100644 index 0000000000..8fddf69f91 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js @@ -0,0 +1,68 @@ +// Copyright 2019 Googe Inc. All rights reserved. +// Copyright 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the order of getting options of 'fractionalSecondDigits' for the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( newTarget, locales, options, required, defaults ) + ... + 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). + ... + 36. For each row of Table 7, except the header row, in table order, do + a. Let prop be the name given in the Property column of the row. + b. If prop is "fractionalSecondDigits", then + i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). + c. Else, + i. Let values be a List whose elements are the strings given in the Values column of the row. + ii. Let value be ? GetOption(options, prop, string, values, undefined). + d. Set formatOptions.[[]] to value. + 37. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit"). + ... +includes: [compareArray.js] +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + +// Just need to ensure fractionalSecondDigits are get +// between "second" and "timeZoneName". +const expected = [ + // CreateDateTimeFormat step 4. + "localeMatcher", + // CreateDateTimeFormat step 36. + "second", + "fractionalSecondDigits", + "timeZoneName", + // CreateDateTimeFormat step 37. + "formatMatcher", +]; + +const actual = []; + +const options = { + get second() { + actual.push("second"); + return "numeric"; + }, + get fractionalSecondDigits() { + actual.push("fractionalSecondDigits"); + return undefined; + }, + get localeMatcher() { + actual.push("localeMatcher"); + return undefined; + }, + get timeZoneName() { + actual.push("timeZoneName"); + return undefined; + }, + get formatMatcher() { + actual.push("formatMatcher"); + return undefined; + }, +}; + +new Intl.DateTimeFormat("en", options); +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js new file mode 100644 index 0000000000..34e92ff711 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js @@ -0,0 +1,127 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the order of getting options for the DateTimeFormat constructor. +includes: [compareArray.js] +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + +// To be merged into constructor-options-order.js when the feature is removed. + +const expected = [ + // CreateDateTimeFormat step 4. + "localeMatcher", + // CreateDateTimeFormat step 12. + "hour12", + // CreateDateTimeFormat step 13. + "hourCycle", + // CreateDateTimeFormat step 29. + "timeZone", + // CreateDateTimeFormat step 36. + "weekday", + "era", + "year", + "month", + "day", + "hour", + "minute", + "second", + "timeZoneName", + "formatMatcher", + // CreateDateTimeFormat step 38. + "dateStyle", + // CreateDateTimeFormat step 40. + "timeStyle", +]; + +const actual = []; + +const options = { + get dateStyle() { + actual.push("dateStyle"); + return undefined; + }, + + get day() { + actual.push("day"); + return "numeric"; + }, + + get era() { + actual.push("era"); + return "long"; + }, + + get formatMatcher() { + actual.push("formatMatcher"); + return "best fit"; + }, + + get hour() { + actual.push("hour"); + return "numeric"; + }, + + get hour12() { + actual.push("hour12"); + return true; + }, + + get hourCycle() { + actual.push("hourCycle"); + return "h24"; + }, + + get localeMatcher() { + actual.push("localeMatcher"); + return "best fit"; + }, + + get minute() { + actual.push("minute"); + return "numeric"; + }, + + get month() { + actual.push("month"); + return "numeric"; + }, + + get second() { + actual.push("second"); + return "numeric"; + }, + + get timeStyle() { + actual.push("timeStyle"); + return undefined; + }, + + get timeZone() { + actual.push("timeZone"); + return "UTC"; + }, + + get timeZoneName() { + actual.push("timeZoneName"); + return "long"; + }, + + get weekday() { + actual.push("weekday"); + return "long"; + }, + + get year() { + actual.push("year"); + return "numeric"; + }, +}; + +new Intl.DateTimeFormat("en", options); + +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js new file mode 100644 index 0000000000..1b12975daf --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js @@ -0,0 +1,111 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the order of getting options for the DateTimeFormat constructor. +includes: [compareArray.js] +---*/ + +const expected = [ + // CreateDateTimeFormat step 4. + "localeMatcher", + // CreateDateTimeFormat step 12. + "hour12", + // CreateDateTimeFormat step 13. + "hourCycle", + // CreateDateTimeFormat step 29. + "timeZone", + // CreateDateTimeFormat step 36. + "weekday", + "era", + "year", + "month", + "day", + "hour", + "minute", + "second", + "timeZoneName", + // CreateDateTimeFormat step 37. + "formatMatcher", +]; + +const actual = []; + +const options = { + get day() { + actual.push("day"); + return "numeric"; + }, + + get era() { + actual.push("era"); + return "long"; + }, + + get formatMatcher() { + actual.push("formatMatcher"); + return "best fit"; + }, + + get hour() { + actual.push("hour"); + return "numeric"; + }, + + get hour12() { + actual.push("hour12"); + return true; + }, + + get hourCycle() { + actual.push("hourCycle"); + return "h24"; + }, + + get localeMatcher() { + actual.push("localeMatcher"); + return "best fit"; + }, + + get minute() { + actual.push("minute"); + return "numeric"; + }, + + get month() { + actual.push("month"); + return "numeric"; + }, + + get second() { + actual.push("second"); + return "numeric"; + }, + + get timeZone() { + actual.push("timeZone"); + return "UTC"; + }, + + get timeZoneName() { + actual.push("timeZoneName"); + return "long"; + }, + + get weekday() { + actual.push("weekday"); + return "long"; + }, + + get year() { + actual.push("year"); + return "numeric"; + }, +}; + +new Intl.DateTimeFormat("en", options); + +assert.compareArray(actual, expected); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js new file mode 100644 index 0000000000..9d8419a8af --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js @@ -0,0 +1,47 @@ +// Copyright 2021 Kate Miháliková. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Conflicting properties of dateStyle/timeStyle must be rejected with a TypeError for the options argument to the DateTimeFormat constructor. +info: | + InitializeDateTimeFormat ( dateTimeFormat, locales, options ) + + ... + 43. If dateStyle is not undefined or timeStyle is not undefined, then + a. If hasExplicitFormatComponents is true, then + i. Throw a TypeError exception. + b. If required is date and timeStyle is not undefined, then + i. Throw a TypeError exception. + c. If required is time and dateStyle is not undefined, then + i. Throw a TypeError exception. +---*/ + + +// Table 4 - Property column + example value from Values column +const conflictingOptions = [ + [ "weekday", "short" ], + [ "era", "short" ], + [ "year", "numeric" ], + [ "month", "numeric" ], + [ "day", "numeric" ], + [ "dayPeriod", "short" ], + [ "hour", "numeric" ], + [ "minute", "numeric" ], + [ "second", "numeric" ], + [ "fractionalSecondDigits", 3 ], + [ "timeZoneName", "short" ], +]; + +for (const [ option, value ] of conflictingOptions) { + assert.throws(TypeError, function() { + new Intl.DateTimeFormat("en", { [option]: value, dateStyle: "short" }); + }, `new Intl.DateTimeFormat("en", { ${option}: "${value}", dateStyle: "short" }) throws TypeError`); + + assert.throws(TypeError, function() { + new Intl.DateTimeFormat("en", { [option]: value, timeStyle: "short" }); + }, `new Intl.DateTimeFormat("en", { ${option}: "${value}", timeStyle: "short" }) throws TypeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js new file mode 100644 index 0000000000..79260c8ef7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js @@ -0,0 +1,26 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor. +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +function CustomError() {} + +const options = [ + "dayPeriod", +]; + +for (const option of options) { + assert.throws(CustomError, () => { + new Intl.DateTimeFormat("en", { + get [option]() { + throw new CustomError(); + } + }); + }, `Exception from ${option} getter should be propagated`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js new file mode 100644 index 0000000000..2ff4078376 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js @@ -0,0 +1,26 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor. +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + +function CustomError() {} + +const options = [ + "fractionalSecondDigits", +]; + +for (const option of options) { + assert.throws(CustomError, () => { + new Intl.DateTimeFormat("en", { + get [option]() { + throw new CustomError(); + } + }); + }, `Exception from ${option} getter should be propagated`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js new file mode 100644 index 0000000000..1e23c09bc2 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js @@ -0,0 +1,31 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor. +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + +// To be merged into constructor-options-throwing-getters.js when the feature is removed. + +function CustomError() {} + +const options = [ + // CreateDateTimeFormat step 39 + "dateStyle", + // CreateDateTimeFormat step 41 + "timeStyle", +]; + +for (const option of options) { + assert.throws(CustomError, () => { + new Intl.DateTimeFormat("en", { + get [option]() { + throw new CustomError(); + } + }); + }, `Exception from ${option} getter should be propagated`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js new file mode 100644 index 0000000000..2eead83306 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js @@ -0,0 +1,33 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor. +---*/ + +function CustomError() {} + +const options = [ + "weekday", "year", "month", "day", + "hour", "minute", "second", + "localeMatcher", + "hour12", + "hourCycle", + "timeZone", + "era", + "timeZoneName", + "formatMatcher", +]; + +for (const option of options) { + assert.throws(CustomError, () => { + new Intl.DateTimeFormat("en", { + get [option]() { + throw new CustomError(); + } + }); + }, `Exception from ${option} getter should be propagated`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js new file mode 100644 index 0000000000..0bb3b18afa --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js @@ -0,0 +1,31 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks error cases for the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + + ... + 41. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined). +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + + +const invalidOptions = [ + "", + "FULL", + " long", + "short ", + "narrow", + "numeric", +]; +for (const timeStyle of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.DateTimeFormat("en", { timeStyle }); + }, `new Intl.DateTimeFormat("en", { timeStyle: "${timeStyle}" }) throws RangeError`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js new file mode 100644 index 0000000000..f8bad0acda --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js @@ -0,0 +1,38 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks handling of the options argument to the DateTimeFormat constructor. +info: | + CreateDateTimeFormat ( dateTimeFormat, locales, options, required, default ) + + ... + 41. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). + 42. Set dateTimeFormat.[[TimeStyle]] to timeStyle. +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + +const validOptions = [ + [undefined, undefined], + ["full", "full"], + ["long", "long"], + ["medium", "medium"], + ["short", "short"], + [{ toString() { return "full"; } }, "full"], + [{ valueOf() { return "long"; }, toString: undefined }, "long"], +]; +for (const [timeStyle, expected] of validOptions) { + const dtf = new Intl.DateTimeFormat("en", { timeStyle }); + const options = dtf.resolvedOptions(); + assert.sameValue(options.timeStyle, expected); + const propdesc = Object.getOwnPropertyDescriptor(options, "timeStyle"); + if (expected === undefined) { + assert.sameValue(propdesc, undefined); + } else { + assert.sameValue(propdesc.value, expected); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js new file mode 100644 index 0000000000..7c37e7c523 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js @@ -0,0 +1,30 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: > + Invalid values for the `timeZoneName` option of the DateTimeFormat constructor +features: [Intl.DateTimeFormat-extend-timezonename] +---*/ + +assert.throws(RangeError, function () { + new Intl.DateTimeFormat('en', { timeZoneName: '' }); +}, 'empty string'); + +assert.throws(RangeError, function () { + new Intl.DateTimeFormat('en', { timeZoneName: 'short ' }); +}, '"short "'); + +assert.throws(RangeError, function () { + new Intl.DateTimeFormat('en', { timeZoneName: ' long' }); +}, '" long"'); + +assert.throws(RangeError, function () { + new Intl.DateTimeFormat('en', { timeZoneName: 'offset' }); +}, '"offset"'); + +assert.throws(RangeError, function () { + new Intl.DateTimeFormat('en', { timeZoneName: 'generic' }); +}, '"generic"'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js new file mode 100644 index 0000000000..cdfc4dcd5c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js @@ -0,0 +1,30 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: > + Valid values for the `timeZoneName` option of the DateTimeFormat constructor +features: [Intl.DateTimeFormat-extend-timezonename] +---*/ + +var dtf; + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'short' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'short'); + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'long' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'long'); + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'shortOffset' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'shortOffset'); + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'longOffset' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'longOffset'); + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'shortGeneric' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'shortGeneric'); + +dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'longGeneric' }); +assert.sameValue(dtf.resolvedOptions().timeZoneName, 'longGeneric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js new file mode 100644 index 0000000000..6f449b023b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js @@ -0,0 +1,40 @@ +// Copyright (C) 2018 Ujjwal Sharma. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that Intl.DateTimeFormat contructor converts the options argument + to an object using `ToObject` (7.1.13). + +---*/ + +const toObjectResults = [ + [true, new Boolean(true)], + [42, new Number(42)], + ['foo', new String('foo')], + [{}, {}], + [Symbol(), Object(Symbol())] +]; + +// Test if ToObject is used to convert primitives to Objects. +toObjectResults.forEach(pair => { + const [value, result] = pair; + + const actual = new Intl.DateTimeFormat(['en-US'], value).resolvedOptions(); + const expected = new Intl.DateTimeFormat(['en-US'], result).resolvedOptions(); + + assert.sameValue(actual.locale, expected.locale); + assert.sameValue(actual.calendar, expected.calendar); + assert.sameValue(actual.day, expected.day); + assert.sameValue(actual.month, expected.month); + assert.sameValue(actual.year, expected.year); + assert.sameValue(actual.numberingSystem, expected.numberingSystem); + assert.sameValue(actual.timeZone, expected.timeZone); +}); + +// ToObject throws a TypeError for undefined and null, but it's not called +// when options is undefined. +assert.throws(TypeError, () => new Intl.DateTimeFormat(['en-US'], null)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js b/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js new file mode 100644 index 0000000000..bfe57ade97 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js @@ -0,0 +1,106 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_TDTO +description: > + Tests that the set of options for the date and time components is + processed correctly. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +var locales = [[], ["zh-Hans-CN"], ["hi-IN"], ["en-US"], ["id-ID"]]; +var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))]; + +function testWithDateTimeFormat(options, expected) { + locales.forEach(function (locales) { + var format = new Intl.DateTimeFormat(locales, options); + var resolvedOptions = format.resolvedOptions(); + getDateTimeComponents().forEach(function (component) { + if (resolvedOptions.hasOwnProperty(component)) { + assert(expected.hasOwnProperty(component), + "Unrequested component " + component + + " added to expected subset " + JSON.stringify(expected) + + "; locales " + locales + ", options " + + (options ? JSON.stringify(options) : options) + "."); + } else { + assert.sameValue(expected.hasOwnProperty(component), false, + "Missing component " + component + + " from expected subset " + JSON.stringify(expected) + + "; locales " + locales + ", options " + + (options ? JSON.stringify(options) : options) + "."); + } + }); + }); +} + +function testWithToLocale(f, options, expected) { + // expected can be either one subset or an array of possible subsets + if (expected.length === undefined) { + expected = [expected]; + } + locales.forEach(function (locales) { + dates.forEach(function (date) { + var formatted = Date.prototype[f].call(date, locales, options); + var expectedStrings = []; + expected.forEach(function (expected) { + var referenceFormat = new Intl.DateTimeFormat(locales, expected); + expectedStrings.push(referenceFormat.format(date)); + }); + assert.notSameValue(expectedStrings.indexOf(formatted), -1, + "Function " + f + " did not return expected string for locales " + + locales + ", options " + (options? JSON.stringify(options) : options) + + "; expected " + + (expectedStrings.length === 1 ? expectedStrings[0] : "one of " + expectedStrings) + + ", got " + formatted + "."); + }); + }); +} + +// any/date: steps 5a, 6a, 7a +testWithDateTimeFormat(undefined, {year: "numeric", month: "numeric", day: "numeric"}); + +// any/date: steps 5a, 6a +testWithDateTimeFormat({year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// any/date: steps 5a, 6a +testWithDateTimeFormat({hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + +// any/all: steps 5a, 6a, 7a, 8a +testWithToLocale("toLocaleString", undefined, [ + // the first one is not guaranteed to be supported; the second one is + {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"} +]); + +// any/all: steps 5a, 6a +testWithToLocale("toLocaleString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// any/all: steps 5a, 6a +testWithToLocale("toLocaleString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + +// date/date: steps 5a, 7a +testWithToLocale("toLocaleDateString", undefined, {year: "numeric", month: "numeric", day: "numeric"}); + +// date/date: steps 5a +testWithToLocale("toLocaleDateString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// date/date: steps 5a, 7a +testWithToLocale("toLocaleDateString", {hour: "numeric", minute: "numeric", second: "numeric"}, [ + // the first one is not guaranteed to be supported; the second one is + {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"} +]); + +// time/time: steps 6a, 8a +testWithToLocale("toLocaleTimeString", undefined, {hour: "numeric", minute: "numeric", second: "numeric"}); + +// time/time: steps 6a, 8a +testWithToLocale("toLocaleTimeString", {weekday: "short", year: "numeric", month: "numeric", day: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}); + +// time/time: steps 6a +testWithToLocale("toLocaleTimeString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js new file mode 100644 index 0000000000..854e5ff3f1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js @@ -0,0 +1,22 @@ +// Copyright (C) 2017 Daniel Ehrenberg. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-todatetimeoptions +description: > + Monkey-patching Object.prototype does not change the default + options for DateTimeFormat as a null prototype is used. +info: | + ToDateTimeOptions ( options, required, defaults ) + + 1. If options is undefined, let options be null; otherwise let options be ? ToObject(options). + 1. Let options be ObjectCreate(options). +---*/ + +let defaultYear = new Intl.DateTimeFormat("en").resolvedOptions().year; + +Object.prototype.year = "2-digit"; +let formatter = new Intl.DateTimeFormat("en"); +assert.sameValue(formatter.resolvedOptions().year, defaultYear); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js b/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js new file mode 100644 index 0000000000..34c9829741 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js @@ -0,0 +1,39 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.2.3_b +description: > + Tests that Intl.DateTimeFormat does not accept Unicode locale + extension keys and values that are not allowed. +author: Norbert Lindenberg +---*/ + +var locales = ["ja-JP", "zh-Hans-CN", "zh-Hant-TW"]; +var input = new Date(Date.parse("1989-11-09T17:57:00Z")); + +locales.forEach(function (locale) { + var defaultDateTimeFormat = new Intl.DateTimeFormat([locale]); + var defaultOptions = defaultDateTimeFormat.resolvedOptions(); + var defaultOptionsJSON = JSON.stringify(defaultOptions); + var defaultLocale = defaultOptions.locale; + var defaultFormatted = defaultDateTimeFormat.format(input); + + var keyValues = { + "cu": ["USD", "EUR", "JPY", "CNY", "TWD", "invalid"], // DateTimeFormat internally uses NumberFormat + "nu": ["native", "traditio", "finance", "invalid"], + "tz": ["usnavajo", "utcw01", "aumel", "uslax", "usnyc", "deber", "invalid"] + }; + + Object.getOwnPropertyNames(keyValues).forEach(function (key) { + keyValues[key].forEach(function (value) { + var dateTimeFormat = new Intl.DateTimeFormat([locale + "-u-" + key + "-" + value]); + var options = dateTimeFormat.resolvedOptions(); + assert.sameValue(options.locale, defaultLocale, "Locale " + options.locale + " is affected by key " + key + "; value " + value + "."); + assert.sameValue(JSON.stringify(options), defaultOptionsJSON, "Resolved options " + JSON.stringify(options) + " are affected by key " + key + "; value " + value + "."); + assert.sameValue(dateTimeFormat.format(input), defaultFormatted, "Formatted value " + dateTimeFormat.format(input) + " is affected by key " + key + "; value " + value + "."); + }); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js b/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js new file mode 100644 index 0000000000..34e6873529 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.3 +description: > + Tests that objects constructed by Intl.DateTimeFormat have the + specified internal properties. +author: Norbert Lindenberg +---*/ + +var obj = new Intl.DateTimeFormat(); + +var actualPrototype = Object.getPrototypeOf(obj); +assert.sameValue(actualPrototype, Intl.DateTimeFormat.prototype, "Prototype of object constructed by Intl.DateTimeFormat isn't Intl.DateTimeFormat.prototype."); + +assert(Object.isExtensible(obj), "Object constructed by Intl.DateTimeFormat must be extensible."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js new file mode 100644 index 0000000000..61b9452d9a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js @@ -0,0 +1,34 @@ +// Copyright 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-unwrapdatetimeformat +description: > + Tests that [[FallbackSymbol]]'s [[Description]] is "IntlLegacyConstructedSymbol" if normative optional is implemented. +author: Yusuke Suzuki +features: [intl-normative-optional] +---*/ + +let object = new Intl.DateTimeFormat(); +let newObject = Intl.DateTimeFormat.call(object); +let symbol = null; +let error = null; +try { + let proxy = new Proxy(newObject, { + get(target, property) { + symbol = property; + return target[property]; + } + }); + Intl.DateTimeFormat.prototype.resolvedOptions.call(proxy); +} catch (e) { + // If normative optional is not implemented, an error will be thrown. + error = e; + assert(error instanceof TypeError); +} +if (error === null) { + assert.sameValue(typeof symbol, "symbol"); + assert.sameValue(symbol.description, "IntlLegacyConstructedSymbol"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js new file mode 100644 index 0000000000..6ca345b44e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js @@ -0,0 +1,20 @@ +// Copyright 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat +description: > + Tests that [[FallbackSymbol]]'s [[Description]] is "IntlLegacyConstructedSymbol" if normative optional is implemented. +author: Yusuke Suzuki +features: [intl-normative-optional] +---*/ + +let object = new Intl.DateTimeFormat(); +let newObject = Intl.DateTimeFormat.call(object); +let symbols = Object.getOwnPropertySymbols(newObject); +if (symbols.length !== 0) { + assert.sameValue(symbols.length, 1); + assert.sameValue(symbols[0].description, "IntlLegacyConstructedSymbol"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js b/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js new file mode 100644 index 0000000000..6d44737ef4 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js @@ -0,0 +1,21 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_a +description: > + Tests that constructing a DateTimeFormat doesn't create or modify + unwanted properties on the RegExp constructor. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +testForUnwantedRegExpChanges(function () { + new Intl.DateTimeFormat("de-DE-u-ca-gregory"); +}); + +testForUnwantedRegExpChanges(function () { + new Intl.DateTimeFormat("de-DE-u-ca-gregory", {timeZone: "UTC"}); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/length.js b/js/src/tests/test262/intl402/DateTimeFormat/length.js new file mode 100644 index 0000000000..29563adcd3 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/length.js @@ -0,0 +1,34 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat +description: > + Intl.DateTimeFormat.length is 0. +info: | + Intl.DateTimeFormat ( [ locales [ , options ] ] ) + + 17 ECMAScript Standard Built-in Objects: + + Every built-in function object, including constructors, has a length + property whose value is an integer. Unless otherwise specified, this + value is equal to the largest number of named arguments shown in the + subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which + are shown using the form «...name») are not included in the default + argument count. + Unless otherwise specified, the length property of a built-in function + object has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: true }. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/name.js b/js/src/tests/test262/intl402/DateTimeFormat/name.js new file mode 100644 index 0000000000..fbdc7f6cab --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2016 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat +description: > + Intl.DateTimeFormat.name is "DateTimeFormat". +info: | + 12.2.1 Intl.DateTimeFormat ([ locales [ , options ]]) + + 17 ECMAScript Standard Built-in Objects: + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value + is a String. + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat, "name", { + value: "DateTimeFormat", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js b/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js new file mode 100644 index 0000000000..baa730596c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js @@ -0,0 +1,69 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that the options numberingSystem and calendar can be set through + either the locale or the options. +author: Norbert Lindenberg, Daniel Ehrenberg +---*/ + +let defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale; + +let supportedNumberingSystems = ["latn", "arab"].filter(nu => + new Intl.DateTimeFormat(defaultLocale + "-u-nu-" + nu) + .resolvedOptions().numberingSystem === nu +); + +let supportedCalendars = ["gregory", "chinese"].filter(ca => + new Intl.DateTimeFormat(defaultLocale + "-u-ca-" + ca) + .resolvedOptions().calendar === ca +); + +let options = [ + {key: "nu", property: "numberingSystem", type: "string", values: supportedNumberingSystems}, + {key: "ca", property: "calendar", type: "string", values: supportedCalendars} +]; + +options.forEach(function (option) { + let dateTimeFormat, opt, result; + + // find out which values are supported for a property in the default locale + let supportedValues = []; + option.values.forEach(function (value) { + opt = {}; + opt[option.property] = value; + dateTimeFormat = new Intl.DateTimeFormat([defaultLocale], opt); + result = dateTimeFormat.resolvedOptions()[option.property]; + if (result !== undefined && supportedValues.indexOf(result) === -1) { + supportedValues.push(result); + } + }); + + // verify that the supported values can also be set through the locale + supportedValues.forEach(function (value) { + dateTimeFormat = new Intl.DateTimeFormat([defaultLocale + "-u-" + option.key + "-" + value]); + result = dateTimeFormat.resolvedOptions()[option.property]; + assert.sameValue(result, value, "Property " + option.property + " couldn't be set through locale extension key " + option.key + "."); + }); + + // verify that the options setting overrides the locale setting + supportedValues.forEach(function (value) { + let otherValue; + option.values.forEach(function (possibleValue) { + if (possibleValue !== value) { + otherValue = possibleValue; + } + }); + if (otherValue !== undefined) { + opt = {}; + opt[option.property] = value; + dateTimeFormat = new Intl.DateTimeFormat([defaultLocale + "-u-" + option.key + "-" + otherValue], opt); + result = dateTimeFormat.resolvedOptions()[option.property]; + assert.sameValue(result, value, "Options value for property " + option.property + " doesn't override locale extension key " + option.key + "."); + } + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js new file mode 100644 index 0000000000..c2b774815d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat-intro +description: > + "DateTimeFormat" property of Intl. +info: | + Intl.DateTimeFormat (...) + + 7 Requirements for Standard Built-in ECMAScript Objects + + Unless specified otherwise in this document, the objects, functions, and constructors + described in this standard are subject to the generic requirements and restrictions + specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language + Specification, 9th edition, clause 17, or successor. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 has the + attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } + unless otherwise specified. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl, "DateTimeFormat", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js b/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js new file mode 100644 index 0000000000..118fadf545 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js @@ -0,0 +1,60 @@ +// Copyright (C) 2019 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat +description: Default [[Prototype]] value derived from realm of the NewTarget. +info: | + Intl.DateTimeFormat ( [ locales [ , options ] ] ) + + 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. + 2. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%DateTimeFormatPrototype%", « ... »). + ... + 6. Return dateTimeFormat. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + ... + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [cross-realm, Reflect, Symbol] +---*/ + +var other = $262.createRealm().global; +var newTarget = new other.Function(); +var dtf; + +newTarget.prototype = undefined; +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = false; +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = 'str'; +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget); +assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Number'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js new file mode 100644 index 0000000000..dd849faaef --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.3_L15 +description: > + Tests that Intl.DateTimeFormat.prototype meets the requirements + for built-in objects defined by the introduction of chapter 17 of + the ECMAScript Language Specification. +author: Norbert Lindenberg +---*/ + +assert(Object.isExtensible(Intl.DateTimeFormat.prototype), "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.prototype), Object.prototype, + "Built-in prototype objects must have Object.prototype as their prototype."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js new file mode 100644 index 0000000000..6d19563ee2 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.constructor +description: > + "constructor" property of Intl.DateTimeFormat.prototype. +info: | + Intl.DateTimeFormat.prototype.constructor + + 7 Requirements for Standard Built-in ECMAScript Objects + + Unless specified otherwise in this document, the objects, functions, and constructors + described in this standard are subject to the generic requirements and restrictions + specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language + Specification, 9th edition, clause 17, or successor. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 has the + attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } + unless otherwise specified. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.prototype, "constructor", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js new file mode 100644 index 0000000000..5092db0768 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js @@ -0,0 +1,14 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3.1 +description: > + Tests that Intl.DateTimeFormat.prototype.constructor is the + Intl.DateTimeFormat. +author: Roozbeh Pournader +---*/ + +assert.sameValue(Intl.DateTimeFormat.prototype.constructor, Intl.DateTimeFormat, "Intl.DateTimeFormat.prototype.constructor is not the same as Intl.DateTimeFormat"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js new file mode 100644 index 0000000000..485a7c0720 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js @@ -0,0 +1,30 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3.2_1_c +description: Tests that format function is bound to its Intl.DateTimeFormat. +author: Norbert Lindenberg +---*/ + +var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))]; +var locales = [undefined, ["de"], ["th-u-ca-gregory-nu-thai"], ["en"], ["ja-u-ca-japanese"], ["ar-u-ca-islamicc-nu-arab"]]; +var options = [ + undefined, + {hour12: false}, + {month: "long", day: "numeric", hour: "2-digit", minute: "2-digit"} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var formatObj = new Intl.DateTimeFormat(locales, options); + var formatFunc = formatObj.format; + dates.forEach(function (date) { + var referenceFormatted = formatObj.format(date); + var formatted = formatFunc(date); + assert.sameValue(referenceFormatted, formatted, "format function produces different result than format method for locales " + locales + "; options: " + (options ? JSON.stringify(options) : options) + "."); + }); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js new file mode 100644 index 0000000000..c4870b0b57 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.3.2_L15 +description: > + Tests that the getter for Intl.DateTimeFormat.prototype.format + meets the requirements for built-in objects defined by the + introduction of chapter 17 of the ECMAScript Language + Specification. +author: Norbert Lindenberg +includes: [isConstructor.js] +features: [Reflect.construct] +---*/ + +var formatFn = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get; + +assert.sameValue(Object.prototype.toString.call(formatFn), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(formatFn), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(formatFn), Function.prototype); + +assert.sameValue(formatFn.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(formatFn), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js new file mode 100644 index 0000000000..f13f9425ce --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js @@ -0,0 +1,38 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + The Date constructor is not called to convert the input value. +info: > + 12.1.5 DateTime Format Functions + + ... + 3. If date is not provided or is undefined, then + ... + 4. Else, + a. Let x be ? ToNumber(date). + 5. Return FormatDateTime(dtf, x). + + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. ... +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var dateTimeString = "2017-11-10T14:09:00.000Z"; + +// |dateTimeString| is valid ISO-8601 style date/time string. +assert.notSameValue(new Date(dateTimeString), NaN); + +// Ensure string input values are not converted to time values by calling the +// Date constructor. +assert.throws(RangeError, function() { + dtf.format(dateTimeString); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js new file mode 100644 index 0000000000..13b8f374b3 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js @@ -0,0 +1,95 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of dayPeriod, long format. +features: [Intl.DateTimeFormat-dayPeriod] +locale: [en-US] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const long = new Intl.DateTimeFormat('en', { + dayPeriod: 'long' +}); + +assert.sameValue(long.format(d0000), 'at night', '00:00, long format'); +assert.sameValue(long.format(d0100), 'at night', '01:00, long format'); +assert.sameValue(long.format(d0200), 'at night', '02:00, long format'); +assert.sameValue(long.format(d0300), 'at night', '03:00, long format'); +assert.sameValue(long.format(d0400), 'at night', '04:00, long format'); +assert.sameValue(long.format(d0500), 'at night', '05:00, long format'); +assert.sameValue(long.format(d0600), 'in the morning', '06:00, long format'); +assert.sameValue(long.format(d0700), 'in the morning', '07:00, long format'); +assert.sameValue(long.format(d0800), 'in the morning', '08:00, long format'); +assert.sameValue(long.format(d0900), 'in the morning', '09:00, long format'); +assert.sameValue(long.format(d1000), 'in the morning', '10:00, long format'); +assert.sameValue(long.format(d1100), 'in the morning', '11:00, long format'); +assert.sameValue(long.format(d1200), 'noon', '12:00, long format'); +assert.sameValue(long.format(d1300), 'in the afternoon', '13:00, long format'); +assert.sameValue(long.format(d1400), 'in the afternoon', '14:00, long format'); +assert.sameValue(long.format(d1500), 'in the afternoon', '15:00, long format'); +assert.sameValue(long.format(d1600), 'in the afternoon', '16:00, long format'); +assert.sameValue(long.format(d1700), 'in the afternoon', '17:00, long format'); +assert.sameValue(long.format(d1800), 'in the evening', '18:00, long format'); +assert.sameValue(long.format(d1900), 'in the evening', '19:00, long format'); +assert.sameValue(long.format(d2000), 'in the evening', '20:00, long format'); +assert.sameValue(long.format(d2100), 'at night', '21:00, long format'); +assert.sameValue(long.format(d2200), 'at night', '22:00, long format'); +assert.sameValue(long.format(d2300), 'at night', '23:00, long format'); + +const longNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'long', + hour: 'numeric' +}); + +assert.sameValue(longNumeric.format(d0000), '12 at night', '00:00, long-numeric'); +assert.sameValue(longNumeric.format(d0100), '1 at night', '01:00, long-numeric'); +assert.sameValue(longNumeric.format(d0200), '2 at night', '02:00, long-numeric'); +assert.sameValue(longNumeric.format(d0300), '3 at night', '03:00, long-numeric'); +assert.sameValue(longNumeric.format(d0400), '4 at night', '04:00, long-numeric'); +assert.sameValue(longNumeric.format(d0500), '5 at night', '05:00, long-numeric'); +assert.sameValue(longNumeric.format(d0600), '6 in the morning', '06:00, long-numeric'); +assert.sameValue(longNumeric.format(d0700), '7 in the morning', '07:00, long-numeric'); +assert.sameValue(longNumeric.format(d0800), '8 in the morning', '08:00, long-numeric'); +assert.sameValue(longNumeric.format(d0900), '9 in the morning', '09:00, long-numeric'); +assert.sameValue(longNumeric.format(d1000), '10 in the morning', '10:00, long-numeric'); +assert.sameValue(longNumeric.format(d1100), '11 in the morning', '11:00, long-numeric'); +assert.sameValue(longNumeric.format(d1200), '12 noon', '12:00, long-numeric'); +assert.sameValue(longNumeric.format(d1300), '1 in the afternoon', '13:00, long-numeric'); +assert.sameValue(longNumeric.format(d1400), '2 in the afternoon', '14:00, long-numeric'); +assert.sameValue(longNumeric.format(d1500), '3 in the afternoon', '15:00, long-numeric'); +assert.sameValue(longNumeric.format(d1600), '4 in the afternoon', '16:00, long-numeric'); +assert.sameValue(longNumeric.format(d1700), '5 in the afternoon', '17:00, long-numeric'); +assert.sameValue(longNumeric.format(d1800), '6 in the evening', '18:00, long-numeric'); +assert.sameValue(longNumeric.format(d1900), '7 in the evening', '19:00, long-numeric'); +assert.sameValue(longNumeric.format(d2000), '8 in the evening', '20:00, long-numeric'); +assert.sameValue(longNumeric.format(d2100), '9 at night', '21:00, long-numeric'); +assert.sameValue(longNumeric.format(d2200), '10 at night', '22:00, long-numeric'); +assert.sameValue(longNumeric.format(d2300), '11 at night', '23:00, long-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js new file mode 100644 index 0000000000..4d26a5131d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js @@ -0,0 +1,95 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of dayPeriod, narrow format. +features: [Intl.DateTimeFormat-dayPeriod] +locale: [en-US] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const narrow = new Intl.DateTimeFormat('en', { + dayPeriod: 'narrow' +}); + +assert.sameValue(narrow.format(d0000), 'at night', '00:00, narrow format'); +assert.sameValue(narrow.format(d0100), 'at night', '01:00, narrow format'); +assert.sameValue(narrow.format(d0200), 'at night', '02:00, narrow format'); +assert.sameValue(narrow.format(d0300), 'at night', '03:00, narrow format'); +assert.sameValue(narrow.format(d0400), 'at night', '04:00, narrow format'); +assert.sameValue(narrow.format(d0500), 'at night', '05:00, narrow format'); +assert.sameValue(narrow.format(d0600), 'in the morning', '06:00, narrow format'); +assert.sameValue(narrow.format(d0700), 'in the morning', '07:00, narrow format'); +assert.sameValue(narrow.format(d0800), 'in the morning', '08:00, narrow format'); +assert.sameValue(narrow.format(d0900), 'in the morning', '09:00, narrow format'); +assert.sameValue(narrow.format(d1000), 'in the morning', '10:00, narrow format'); +assert.sameValue(narrow.format(d1100), 'in the morning', '11:00, narrow format'); +assert.sameValue(narrow.format(d1200), 'n', '12:00, narrow format'); +assert.sameValue(narrow.format(d1300), 'in the afternoon', '13:00, narrow format'); +assert.sameValue(narrow.format(d1400), 'in the afternoon', '14:00, narrow format'); +assert.sameValue(narrow.format(d1500), 'in the afternoon', '15:00, narrow format'); +assert.sameValue(narrow.format(d1600), 'in the afternoon', '16:00, narrow format'); +assert.sameValue(narrow.format(d1700), 'in the afternoon', '17:00, narrow format'); +assert.sameValue(narrow.format(d1800), 'in the evening', '18:00, narrow format'); +assert.sameValue(narrow.format(d1900), 'in the evening', '19:00, narrow format'); +assert.sameValue(narrow.format(d2000), 'in the evening', '20:00, narrow format'); +assert.sameValue(narrow.format(d2100), 'at night', '21:00, narrow format'); +assert.sameValue(narrow.format(d2200), 'at night', '22:00, narrow format'); +assert.sameValue(narrow.format(d2300), 'at night', '23:00, narrow format'); + +const narrowNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'narrow', + hour: 'numeric' +}); + +assert.sameValue(narrowNumeric.format(d0000), '12 at night', '00:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0100), '1 at night', '01:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0200), '2 at night', '02:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0300), '3 at night', '03:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0400), '4 at night', '04:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0500), '5 at night', '05:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0600), '6 in the morning', '06:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0700), '7 in the morning', '07:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0800), '8 in the morning', '08:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d0900), '9 in the morning', '09:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1000), '10 in the morning', '10:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1100), '11 in the morning', '11:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1200), '12 n', '12:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1300), '1 in the afternoon', '13:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1400), '2 in the afternoon', '14:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1500), '3 in the afternoon', '15:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1600), '4 in the afternoon', '16:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1700), '5 in the afternoon', '17:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1800), '6 in the evening', '18:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d1900), '7 in the evening', '19:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d2000), '8 in the evening', '20:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d2100), '9 at night', '21:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d2200), '10 at night', '22:00, narrow-numeric'); +assert.sameValue(narrowNumeric.format(d2300), '11 at night', '23:00, narrow-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js new file mode 100644 index 0000000000..f7b410f24d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js @@ -0,0 +1,95 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-initializedatetimeformat +description: Checks basic handling of dayPeriod, short format. +features: [Intl.DateTimeFormat-dayPeriod] +locale: [en-US] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const short = new Intl.DateTimeFormat('en', { + dayPeriod: 'short' +}); + +assert.sameValue(short.format(d0000), 'at night', '00:00, short format'); +assert.sameValue(short.format(d0100), 'at night', '01:00, short format'); +assert.sameValue(short.format(d0200), 'at night', '02:00, short format'); +assert.sameValue(short.format(d0300), 'at night', '03:00, short format'); +assert.sameValue(short.format(d0400), 'at night', '04:00, short format'); +assert.sameValue(short.format(d0500), 'at night', '05:00, short format'); +assert.sameValue(short.format(d0600), 'in the morning', '06:00, short format'); +assert.sameValue(short.format(d0700), 'in the morning', '07:00, short format'); +assert.sameValue(short.format(d0800), 'in the morning', '08:00, short format'); +assert.sameValue(short.format(d0900), 'in the morning', '09:00, short format'); +assert.sameValue(short.format(d1000), 'in the morning', '10:00, short format'); +assert.sameValue(short.format(d1100), 'in the morning', '11:00, short format'); +assert.sameValue(short.format(d1200), 'noon', '12:00, short format'); +assert.sameValue(short.format(d1300), 'in the afternoon', '13:00, short format'); +assert.sameValue(short.format(d1400), 'in the afternoon', '14:00, short format'); +assert.sameValue(short.format(d1500), 'in the afternoon', '15:00, short format'); +assert.sameValue(short.format(d1600), 'in the afternoon', '16:00, short format'); +assert.sameValue(short.format(d1700), 'in the afternoon', '17:00, short format'); +assert.sameValue(short.format(d1800), 'in the evening', '18:00, short format'); +assert.sameValue(short.format(d1900), 'in the evening', '19:00, short format'); +assert.sameValue(short.format(d2000), 'in the evening', '20:00, short format'); +assert.sameValue(short.format(d2100), 'at night', '21:00, short format'); +assert.sameValue(short.format(d2200), 'at night', '22:00, short format'); +assert.sameValue(short.format(d2300), 'at night', '23:00, short format'); + +const shortNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'short', + hour: 'numeric' +}); + +assert.sameValue(shortNumeric.format(d0000), '12 at night', '00:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0100), '1 at night', '01:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0200), '2 at night', '02:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0300), '3 at night', '03:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0400), '4 at night', '04:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0500), '5 at night', '05:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0600), '6 in the morning', '06:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0700), '7 in the morning', '07:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0800), '8 in the morning', '08:00, short-numeric'); +assert.sameValue(shortNumeric.format(d0900), '9 in the morning', '09:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1000), '10 in the morning', '10:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1100), '11 in the morning', '11:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1200), '12 noon', '12:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1300), '1 in the afternoon', '13:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1400), '2 in the afternoon', '14:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1500), '3 in the afternoon', '15:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1600), '4 in the afternoon', '16:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1700), '5 in the afternoon', '17:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1800), '6 in the evening', '18:00, short-numeric'); +assert.sameValue(shortNumeric.format(d1900), '7 in the evening', '19:00, short-numeric'); +assert.sameValue(shortNumeric.format(d2000), '8 in the evening', '20:00, short-numeric'); +assert.sameValue(shortNumeric.format(d2100), '9 at night', '21:00, short-numeric'); +assert.sameValue(shortNumeric.format(d2200), '10 at night', '22:00, short-numeric'); +assert.sameValue(shortNumeric.format(d2300), '11 at night', '23:00, short-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js new file mode 100644 index 0000000000..d5270e354a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.3.2_1_a_L15 +description: > + Tests that the function returned by + Intl.DateTimeFormat.prototype.format meets the requirements for + built-in objects defined by the introduction of chapter 17 of the + ECMAScript Language Specification. +author: Norbert Lindenberg +includes: [isConstructor.js] +features: [Reflect.construct] +---*/ + +var formatFn = new Intl.DateTimeFormat().format; + +assert.sameValue(Object.prototype.toString.call(formatFn), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(formatFn), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(formatFn), Function.prototype); + +assert.sameValue(formatFn.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(formatFn), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js new file mode 100644 index 0000000000..255417c98a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js @@ -0,0 +1,31 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.format +description: > + The length of the bound DateTime Format function is 1. +info: | + get Intl.DateTimeFormat.prototype.format + + ... + 4. If dtf.[[BoundFormat]] is undefined, then + a. Let F be a new built-in function object as defined in DateTime Format Functions (12.1.5). + b. Let bf be BoundFunctionCreate(F, dft, « »). + c. Perform ! DefinePropertyOrThrow(bf, "length", PropertyDescriptor {[[Value]]: 1, + [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}). + ... + +includes: [propertyHelper.js] +---*/ + +var formatFn = new Intl.DateTimeFormat().format; + +verifyProperty(formatFn, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js new file mode 100644 index 0000000000..73922bca5f --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js @@ -0,0 +1,28 @@ +// Copyright (C) 2016 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.format +description: > + The bound DateTimeFormat format function is an anonymous function. +info: | + 12.4.3 get Intl.DateTimeFormat.prototype.compare + + 17 ECMAScript Standard Built-in Objects: + Every built-in function object, including constructors, has a `name` + property whose value is a String. Functions that are identified as + anonymous functions use the empty string as the value of the `name` + property. + Unless otherwise specified, the `name` property of a built-in function + object has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, + [[Configurable]]: *true* }. +includes: [propertyHelper.js] +---*/ + +var formatFn = new Intl.DateTimeFormat().format; + +verifyProperty(formatFn, "name", { + value: "", writable: false, enumerable: false, configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js new file mode 100644 index 0000000000..78fcf6950b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js @@ -0,0 +1,18 @@ +// Copyright (C) 2020 ExE Boss. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createbuiltinfunction +description: DateTimeFormat bound format function property order +info: | + Set order: "length", "name" +includes: [compareArray.js] +---*/ + +var formatFn = new Intl.DateTimeFormat().format; + +assert.compareArray( + Object.getOwnPropertyNames(formatFn), + ['length', 'name'] +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js new file mode 100644 index 0000000000..25af5ada6d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js @@ -0,0 +1,34 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of fractionalSecondDigits. +features: [Intl.DateTimeFormat-fractionalSecondDigits] +locale: [en-US] +---*/ + +const d1 = new Date(2019, 7, 10, 1, 2, 3, 234); +const d2 = new Date(2019, 7, 10, 1, 2, 3, 567); + +let dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined}); +assert.sameValue(dtf.format(d1), "02:03", "no fractionalSecondDigits"); +assert.sameValue(dtf.format(d2), "02:03", "no fractionalSecondDigits"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1}); +assert.sameValue(dtf.format(d1), "02:03.2", "1 fractionalSecondDigits round down"); +assert.sameValue(dtf.format(d2), "02:03.5", "1 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2}); +assert.sameValue(dtf.format(d1), "02:03.23", "2 fractionalSecondDigits round down"); +assert.sameValue(dtf.format(d2), "02:03.56", "2 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3}); +assert.sameValue(dtf.format(d1), "02:03.234", "3 fractionalSecondDigits round down"); +assert.sameValue(dtf.format(d2), "02:03.567", "3 fractionalSecondDigits round down"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js new file mode 100644 index 0000000000..fe1ec0b080 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js @@ -0,0 +1,36 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.format +description: > + get Intl.DateTimeFormat.prototype.format.length is 0. +info: | + get Intl.DateTimeFormat.prototype.format + + 17 ECMAScript Standard Built-in Objects: + + Every built-in function object, including constructors, has a length + property whose value is an integer. Unless otherwise specified, this + value is equal to the largest number of named arguments shown in the + subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which + are shown using the form «...name») are not included in the default + argument count. + Unless otherwise specified, the length property of a built-in function + object has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: true }. + +includes: [propertyHelper.js] +---*/ + +var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format"); + +verifyProperty(desc.get, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js new file mode 100644 index 0000000000..3f7419112f --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js @@ -0,0 +1,31 @@ +// Copyright (C) 2016 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.format +description: > + get Intl.DateTimeFormat.prototype.format.name is "get format". +info: | + 12.4.3 get Intl.DateTimeFormat.prototype.format + + 17 ECMAScript Standard Built-in Objects: + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value + is a String. + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +---*/ + +var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format"); + +verifyProperty(desc.get, "name", { + value: "get format", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js new file mode 100644 index 0000000000..010d55def0 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.format +description: > + Tests that Intl.DateTimeFormat.prototype.format calls + OrdinaryHasInstance instead of the instanceof operator which includes a + Symbol.hasInstance lookup and call among other things. +info: > + UnwrapDateTimeFormat ( dtf ) + 2. If dtf does not have an [[InitializedDateTimeFormat]] internal slot and + ? OrdinaryHasInstance(%DateTimeFormat%, dtf) is true, then + a. Return ? Get(dtf, %Intl%.[[FallbackSymbol]]). +---*/ + +const dtf = Object.create(Intl.DateTimeFormat.prototype); + +Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, { + get() { throw new Test262Error(); } +}); + +assert.throws(TypeError, () => dtf.format); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js new file mode 100644 index 0000000000..2f03dcae06 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js @@ -0,0 +1,29 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: > + Tests that date and time formatting in an offset time zone + matches that in the equivalent Etc/GMT±n time zone. +---*/ +let offsetTimeZones = { + '+0300': 'Etc/GMT-3', + '+1400': 'Etc/GMT-14', + '+02': 'Etc/GMT-2', + '+13:00': 'Etc/GMT-13', + '-07:00': 'Etc/GMT+7', + '-12': 'Etc/GMT+12', + '−0900': 'Etc/GMT+9', + '−10:00': 'Etc/GMT+10', + '−0500': 'Etc/GMT+5', +}; +let date = new Date('1995-12-17T03:24:56Z'); +Object.entries(offsetTimeZones).forEach(([offsetZone, gmtZone]) => { + let offsetDf = new Intl.DateTimeFormat("en", + {timeZone: offsetZone, dateStyle: "short", timeStyle: "short"}); + let gmtDf = new Intl.DateTimeFormat("en", + {timeZone: gmtZone, dateStyle: "short", timeStyle: "short"}); + assert.sameValue(offsetDf.format(date), gmtDf.format(date), `${offsetZone} vs. ${gmtZone}:`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js new file mode 100644 index 0000000000..c7f826ddfb --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3.2_FDT_7_a_iv +description: > + Tests that format uses a proleptic Gregorian calendar with no year + 0. +author: Norbert Lindenberg +---*/ + +var dates = [ + 0, // January 1, 1970 + -62151602400000, // in June 1 BC + -8640000000000000 // beginning of ECMAScript time +]; + +var format = new Intl.DateTimeFormat(["en-US"], {year: "numeric", era: "short", timeZone: "UTC"}); + +// this test requires a Gregorian calendar, which we usually find in the US +assert.sameValue(format.resolvedOptions().calendar, "gregory", "Internal error: Didn't find Gregorian calendar"); + +dates.forEach(function (date) { + var year = new Date(date).getUTCFullYear(); + var expectedYear = year <= 0 ? 1 - year : year; + var expectedYearString = expectedYear.toLocaleString(["en-US"], {useGrouping: false}); + var expectedEra = year <= 0 ? /BC/ : /AD|(?:^|[^B])CE/; + var dateString = format.format(date); + assert.notSameValue(dateString.indexOf(expectedYearString), -1, "Formatted year doesn't contain expected year – expected " + expectedYearString + ", got " + dateString + "."); + assert(expectedEra.test(dateString), "Formatted year doesn't contain expected era – expected " + expectedEra + ", got " + dateString + "."); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js new file mode 100644 index 0000000000..55970d90a1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.format +description: > + "format" property of Intl.DateTimeFormat.prototype. +info: | + get Intl.DateTimeFormat.prototype.format + + 7 Requirements for Standard Built-in ECMAScript Objects + + Unless specified otherwise in this document, the objects, functions, and constructors + described in this standard are subject to the generic requirements and restrictions + specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language + Specification, 9th edition, clause 17, or successor. + + 17 ECMAScript Standard Built-in Objects: + + Every accessor property described in clauses 18 through 26 and in Annex B.2 has the + attributes { [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified. + If only a get accessor function is described, the set accessor function is the default + value, undefined. If only a set accessor is described the get accessor is the default + value, undefined. + +includes: [propertyHelper.js] +---*/ + +var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format"); + +assert.sameValue(desc.set, undefined); +assert.sameValue(typeof desc.get, "function"); + +verifyProperty(Intl.DateTimeFormat.prototype, "format", { + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js new file mode 100644 index 0000000000..46be36f3c1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js @@ -0,0 +1,20 @@ +// Copyright 2019 Google Inc, Igalia S.L. All rights reserved. +// Copyright 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: > + Checks the output of 'relatedYear' and 'yearName' type, and + the choice of pattern based on calendar. +locale: [zh-u-ca-chinese] +features: [Array.prototype.includes] +---*/ + +const df = new Intl.DateTimeFormat("zh-u-ca-chinese", {year: "numeric"}); +const date = new Date(2019, 5, 1); +const formatted = df.format(date); +const expected = ["2019己亥年", "己亥年"]; +assert(expected.includes(formatted)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js new file mode 100644 index 0000000000..985f46c993 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js @@ -0,0 +1,55 @@ +// GENERATED, DO NOT EDIT +// file: dateConstants.js +// Copyright (C) 2009 the Sputnik authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + Collection of date-centric values +defines: + - date_1899_end + - date_1900_start + - date_1969_end + - date_1970_start + - date_1999_end + - date_2000_start + - date_2099_end + - date_2100_start + - start_of_time + - end_of_time +---*/ + +var date_1899_end = -2208988800001; +var date_1900_start = -2208988800000; +var date_1969_end = -1; +var date_1970_start = 0; +var date_1999_end = 946684799999; +var date_2000_start = 946684800000; +var date_2099_end = 4102444799999; +var date_2100_start = 4102444800000; + +var start_of_time = -8.64e15; +var end_of_time = 8.64e15; + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js new file mode 100644 index 0000000000..b4ca8b4b0d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3.2_TLT_2 +description: > + Tests that the behavior of a Record is not affected by + adversarial changes to Object.prototype. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "inDST"]); + +var format = new Intl.DateTimeFormat(); +var time = format.format(); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js new file mode 100644 index 0000000000..e9af1ca9c8 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: A time zone in resolvedOptions with a large offset still produces the correct string +locale: [en] +features: [Temporal] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDayPeriodSpace = + new Intl.DateTimeFormat("en-US", { timeStyle: "short" }) + .formatToParts(0) + .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || ""; + +const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" }); + +const date = new Temporal.PlainDate(2021, 8, 4); +const dateResult = formatter.format(date); +assert.sameValue(dateResult, "8/4/2021", "plain date"); + +const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789); +const datetimeResult1 = formatter.format(datetime1); +assert.sameValue( + datetimeResult1, + `8/4/2021, 12:30:45${usDayPeriodSpace}AM`, + "plain datetime close to beginning of day" +); +const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789); +const datetimeResult2 = formatter.format(datetime2); +assert.sameValue(datetimeResult2, `8/4/2021, 11:30:45${usDayPeriodSpace}PM`, "plain datetime close to end of day"); + +const monthDay = new Temporal.PlainMonthDay(8, 4, "gregory"); +const monthDayResult = formatter.format(monthDay); +assert.sameValue(monthDayResult, "8/4", "plain month-day"); + +const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789); +const timeResult1 = formatter.format(time1); +assert.sameValue(timeResult1, `12:30:45${usDayPeriodSpace}AM`, "plain time close to beginning of day"); +const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789); +const timeResult2 = formatter.format(time2); +assert.sameValue(timeResult2, `11:30:45${usDayPeriodSpace}PM`, "plain time close to end of day"); + +const month = new Temporal.PlainYearMonth(2021, 8, "gregory"); +const monthResult = formatter.format(month); +assert.sameValue(monthResult, "8/2021", "plain year-month"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js new file mode 100644 index 0000000000..d36514f42b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: Temporal.ZonedDateTime is not supported directly in format() +features: [Temporal] +---*/ + +const formatter = new Intl.DateTimeFormat(); + +// Check that TypeError would not be thrown for a different reason +const {timeZone, ...options} = formatter.resolvedOptions(); +const datetime = new Temporal.ZonedDateTime(0n, timeZone); +assert.sameValue(typeof datetime.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds"); + +assert.throws(TypeError, () => formatter.format(datetime), "format() does not support Temporal.ZonedDateTime"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js new file mode 100644 index 0000000000..598b9ec88e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js @@ -0,0 +1,20 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3.2_FDT_1 +description: Tests that format handles non-finite values correctly. +author: Norbert Lindenberg +---*/ + +var invalidValues = [NaN, Infinity, -Infinity]; + +var format = new Intl.DateTimeFormat(); + +invalidValues.forEach(function (value) { + assert.throws(RangeError, function() { + var result = format.format(value); + }, "Invalid value " + value + " was not rejected."); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js new file mode 100644 index 0000000000..0c415ec7ea --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + TimeClip is applied when calling Intl.DateTimeFormat.prototype.format. +info: > + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. ... + + 20.3.1.15 TimeClip ( time ) + ... + 2. If abs(time) > 8.64 × 10^15, return NaN. + ... + +includes: [dateConstants.js] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +// Test values near the start of the ECMAScript time range. +assert.throws(RangeError, function() { + dtf.format(start_of_time - 1); +}); +assert.sameValue(typeof dtf.format(start_of_time), "string"); +assert.sameValue(typeof dtf.format(start_of_time + 1), "string"); + +// Test values near the end of the ECMAScript time range. +assert.sameValue(typeof dtf.format(end_of_time - 1), "string"); +assert.sameValue(typeof dtf.format(end_of_time), "string"); +assert.throws(RangeError, function() { + dtf.format(end_of_time + 1); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js new file mode 100644 index 0000000000..d7fbe4db66 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + TimeClip applies ToInteger on its input value. +info: > + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. ... + + 20.3.1.15 TimeClip ( time ) + ... + 3. Let clippedTime be ! ToInteger(time). + 4. If clippedTime is -0, set clippedTime to +0. + 5. Return clippedTime. +---*/ + +// Switch to a time format instead of using DateTimeFormat's default date-only format. +var dtf = new Intl.DateTimeFormat(undefined, { + hour: "numeric", minute: "numeric", second: "numeric" +}); + +var expected = dtf.format(0); + +assert.sameValue(dtf.format(-0.9), expected, "format(-0.9)"); +assert.sameValue(dtf.format(-0.5), expected, "format(-0.5)"); +assert.sameValue(dtf.format(-0.1), expected, "format(-0.1)"); +assert.sameValue(dtf.format(-Number.MIN_VALUE), expected, "format(-Number.MIN_VALUE)"); +assert.sameValue(dtf.format(-0), expected, "format(-0)"); +assert.sameValue(dtf.format(+0), expected, "format(+0)"); +assert.sameValue(dtf.format(Number.MIN_VALUE), expected, "format(Number.MIN_VALUE)"); +assert.sameValue(dtf.format(0.1), expected, "format(0.1)"); +assert.sameValue(dtf.format(0.5), expected, "format(0.5)"); +assert.sameValue(dtf.format(0.9), expected, "format(0.9)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js new file mode 100644 index 0000000000..36893b5f9a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js @@ -0,0 +1,114 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-date-time-style-pattern +description: Checks basic handling of timeStyle and dateStyle. +features: [Intl.DateTimeFormat-datetimestyle, Array.prototype.includes] +locale: [en-US] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDayPeriodSpace = + new Intl.DateTimeFormat("en-US", { timeStyle: "short" }) + .formatToParts(0) + .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || ""; + +const date = new Date("1886-05-01T14:12:47Z"); +const dateOptions = [ + ["full", "Saturday, May 1, 1886"], + ["long", "May 1, 1886"], + ["medium", "May 1, 1886"], + ["short", "5/1/86"], +]; + +const timeOptions = [ + ["full", `2:12:47${usDayPeriodSpace}PM Coordinated Universal Time`, "14:12:47 Coordinated Universal Time"], + ["long", `2:12:47${usDayPeriodSpace}PM UTC`, "14:12:47 UTC"], + ["medium", `2:12:47${usDayPeriodSpace}PM`, "14:12:47"], + ["short", `2:12${usDayPeriodSpace}PM`, "14:12"], +]; + +const options12 = [ + { "hour12": true }, + { "hourCycle": "h11" }, + { "hourCycle": "h12" }, + { "hourCycle": "h23", "hour12": true }, + { "hourCycle": "h24", "hour12": true }, +]; + +const options24 = [ + { "hour12": false }, + { "hourCycle": "h23" }, + { "hourCycle": "h24" }, + { "hourCycle": "h11", "hour12": false }, + { "hourCycle": "h12", "hour12": false }, +]; + +for (const [dateStyle, expected] of dateOptions) { + const dtf = new Intl.DateTimeFormat("en-US", { + dateStyle, + timeZone: "UTC", + }); + + const dateString = dtf.format(date); + assert.sameValue(dateString, expected, `Result for ${dateStyle}`); +} + +for (const [timeStyle, expected12, expected24] of timeOptions) { + const check = (locale, options, expected) => { + const dtf = new Intl.DateTimeFormat(locale, { + timeStyle, + timeZone: "UTC", + ...options + }); + + const dateString = dtf.format(date); + assert.sameValue(dateString, expected, `Result for ${timeStyle} with ${JSON.stringify(options)}`); + }; + + check("en-US", {}, expected12); + check("en-US-u-hc-h11", {}, expected12); + check("en-US-u-hc-h12", {}, expected12); + check("en-US-u-hc-h23", {}, expected24); + check("en-US-u-hc-h24", {}, expected24); + + for (const hourOptions of options12) { + check("en-US", hourOptions, expected12); + check("en-US-u-hc-h11", hourOptions, expected12); + check("en-US-u-hc-h12", hourOptions, expected12); + check("en-US-u-hc-h23", hourOptions, expected12); + check("en-US-u-hc-h24", hourOptions, expected12); + } + + for (const hourOptions of options24) { + check("en-US", hourOptions, expected24); + check("en-US-u-hc-h11", hourOptions, expected24); + check("en-US-u-hc-h12", hourOptions, expected24); + check("en-US-u-hc-h23", hourOptions, expected24); + check("en-US-u-hc-h24", hourOptions, expected24); + } +} + +for (const [dateStyle, expectedDate] of dateOptions) { + for (const [timeStyle, expectedTime] of timeOptions) { + const dtf = new Intl.DateTimeFormat("en-US", { + dateStyle, + timeStyle, + timeZone: "UTC", + }); + const result1 = [expectedDate, ", ", expectedTime].join(""); + const result2 = [expectedDate, " at ", expectedTime].join(""); + + const dateString = dtf.format(date); + assert.sameValue( + [result1, result2].includes(dateString), + true, + `Result for date=${dateStyle} and time=${timeStyle}` + ); + } +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js new file mode 100644 index 0000000000..ee452b5358 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js @@ -0,0 +1,41 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + The Date constructor is not called to convert the input value. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 8. Return ? FormatDateTimeRange(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const dtf = new Intl.DateTimeFormat(); +const dateTimeString = "2017-11-10T14:09:00.000Z"; +const date = new Date(dateTimeString); +// |dateTimeString| is valid ISO-8601 style date/time string. +assert.notSameValue(date, NaN); + +// ToNumber() will try to parse the string as an integer and yield NaN, rather +// than attempting to parse it like the Date constructor would. +assert.throws(RangeError, function() { + dtf.formatRange(dateTimeString, date); +}); + +assert.throws(RangeError, function() { + dtf.formatRange(date, dateTimeString); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js new file mode 100644 index 0000000000..c6efcad3bf --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js @@ -0,0 +1,49 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatRange. +info: | + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + + TimeClip ( time ) + ... + 2. If abs(time) > 8.64 × 10^15, return NaN. + ... + +includes: [dateConstants.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const dtf = new Intl.DateTimeFormat(); +const date = Date.now(); + +// Test values near the start of the ECMAScript time range. +assert.throws(RangeError, function() { + dtf.formatRange(start_of_time - 1, date); +}); +assert.throws(RangeError, function() { + dtf.formatRange(date, start_of_time - 1); +}); +assert.sameValue(typeof dtf.formatRange(start_of_time, date), "string"); +assert.sameValue(typeof dtf.formatRange(start_of_time + 1, date), "string"); + +// Test values near the end of the ECMAScript time range. +assert.sameValue(typeof dtf.formatRange(date, end_of_time - 1), "string"); +assert.sameValue(typeof dtf.formatRange(date, end_of_time), "string"); +assert.throws(RangeError, function() { + dtf.formatRange(end_of_time + 1, date); +}); +assert.throws(RangeError, function() { + dtf.formatRange(date, end_of_time + 1); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js new file mode 100644 index 0000000000..b698b4b9a9 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js @@ -0,0 +1,41 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + TimeClip applies ToInteger on its input value. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + + TimeClip ( time ) + ... + 3. Let clippedTime be ! ToInteger(time). + 4. If clippedTime is -0, set clippedTime to +0. + 5. Return clippedTime. +features: [Intl.DateTimeFormat-formatRange] +---*/ + +// Switch to a time format instead of using DateTimeFormat's default date-only format. +const dtf = new Intl.DateTimeFormat(undefined, { + hour: "numeric", minute: "numeric", second: "numeric" +}); +const date = Date.now(); +const expected = dtf.formatRange(0, date); + +assert.sameValue(dtf.formatRange(-0.9, date), expected, "formatRange(-0.9)"); +assert.sameValue(dtf.formatRange(-0.5, date), expected, "formatRange(-0.5)"); +assert.sameValue(dtf.formatRange(-0.1, date), expected, "formatRange(-0.1)"); +assert.sameValue(dtf.formatRange(-Number.MIN_VALUE, date), expected, "formatRange(-Number.MIN_VALUE)"); +assert.sameValue(dtf.formatRange(-0, date), expected, "formatRange(-0)"); +assert.sameValue(dtf.formatRange(+0, date), expected, "formatRange(+0)"); +assert.sameValue(dtf.formatRange(Number.MIN_VALUE, date), expected, "formatRange(Number.MIN_VALUE)"); +assert.sameValue(dtf.formatRange(0.1, date), expected, "formatRange(0.1)"); +assert.sameValue(dtf.formatRange(0.5, date), expected, "formatRange(0.5)"); +assert.sameValue(dtf.formatRange(0.9, date), expected, "formatRange(0.9)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js new file mode 100644 index 0000000000..ddbe0ed2fe --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js @@ -0,0 +1,56 @@ +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Return abrupt completions from ToNumber(date) +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). +features: [Symbol,Intl.DateTimeFormat-formatRange] +---*/ + +const date = Date.now(); + +const objectValueOf = { + valueOf: function() { + throw new Test262Error(); + } +}; + +const objectToString = { + toString: function() { + throw new Test262Error(); + } +}; + +const dtf = new Intl.DateTimeFormat(["pt-BR"]); + +assert.throws(Test262Error, function() { + dtf.formatRange(objectValueOf, date); +}, "valueOf start"); + +assert.throws(Test262Error, function() { + dtf.formatRange(date, objectValueOf); +}, "valueOf end"); + +assert.throws(Test262Error, function() { + dtf.formatRange(objectToString, date); +}, "toString start"); + +assert.throws(Test262Error, function() { + dtf.formatRange(date, objectToString); +}, "toString end"); + +const s = Symbol('1'); +assert.throws(TypeError, function() { + dtf.formatRange(s, date); +}, "symbol start"); + +assert.throws(TypeError, function() { + dtf.formatRange(date, s); +}, "symbol end"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js new file mode 100644 index 0000000000..d457d6a40b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + Tests that the Intl.DateTimeFormat.prototype.formatRange function meets the + requirements for built-in objects defined by the ECMAScript Language + Specification. +includes: [isConstructor.js] +features: [Reflect.construct,Intl.DateTimeFormat-formatRange] +---*/ + +const formatRange = Intl.DateTimeFormat.prototype.formatRange; + +assert.sameValue(Object.prototype.toString.call(formatRange), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(formatRange), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(formatRange), Function.prototype); + +assert.sameValue(formatRange.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(formatRange), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js new file mode 100644 index 0000000000..d59691d42d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js @@ -0,0 +1,72 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to an Infinity value +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a RangeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 7. If x is greater than y, throw a RangeError exception. + 8. Return ? FormatDateTimeRange(dtf, x, y). + + FormatDateTimeRange ( dateTimeFormat, x, y ) + + 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + + TimeClip ( time ) + 1. If time is not finite, return NaN. + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var date = new Date(); + +assert.throws(RangeError, function() { + dtf.formatRange(Infinity, date); +}, "+Infinity/date"); + +assert.throws(RangeError, function() { + dtf.formatRange(-Infinity, date); +}, "-Infinity/date"); + +assert.throws(RangeError, function() { + dtf.formatRange(date, Infinity); +}, "date/+Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRange(date, -Infinity); +}, "date/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRange(Infinity, Infinity); +}, "+Infinity/+Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRange(-Infinity, -Infinity); +}, "-Infinity/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRange(Infinity, -Infinity); +}, "+Infinity/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRange(-Infinity, Infinity); +}, "-Infinity/+Infinity"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js new file mode 100644 index 0000000000..25d90bafd6 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js @@ -0,0 +1,49 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to NaN +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a RangeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 7. If x is greater than y, throw a RangeError exception. + 8. Return ? FormatDateTimeRange(dtf, x, y). + + FormatDateTimeRange ( dateTimeFormat, x, y ) + + 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var date = new Date(); + +assert.throws(RangeError, function() { + dtf.formatRange(NaN, date); +}, "NaN/date"); + +assert.throws(RangeError, function() { + dtf.formatRange(date, NaN); +}, "date/NaN"); + +assert.throws(RangeError, function() { + dtf.formatRange(NaN, NaN); +}, "NaN/NaN"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js new file mode 100644 index 0000000000..e2dab6cbc1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js @@ -0,0 +1,63 @@ +// Copyright 2021 Google Inc. All rights reserved. +// Copyright 2021 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + When startDate is equal to endDate, the output should be a string equal + to the output of Intl.DateTimeFormat.prototype.format. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 4. Let x be ? ToNumber(startDate). + 5. Let y be ? ToNumber(endDate). + 6. Return ? FormatDateTimeRange(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 13. If dateFieldsPracticallyEqual is true, then + a. Let pattern be dateTimeFormat.[[Pattern]]. + b. Let patternParts be PartitionPattern(pattern). + c. Let result be ? FormatDateTimePattern(dateTimeFormat, patternParts, tm1). + d. For each r in result do + i. Set r.[[Source]] to "shared". + e. Return result. + +features: [Intl.DateTimeFormat-formatRange] +locale: [en-US] +---*/ + +{ + const date = new Date(2019, 7, 10, 1, 2, 3, 234); + + let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" }); + assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with date options"); + + dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" }); + assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with time options"); + + dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" }); + assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with date-time options"); + + dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }); + assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with dateStyle/timeStyle"); +} +{ + const date1 = new Date(2019, 7, 10, 1, 2, 3, 234); + const date2 = new Date(2019, 7, 10, 1, 2, 3, 235); + + let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" }); + assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with date options"); + + dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" }); + assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with time options"); + + dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" }); + assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with date-time options"); + + dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }); + assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with dateStyle/timeStyle"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js new file mode 100644 index 0000000000..639d941101 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js @@ -0,0 +1,44 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if startDate or endDate is undefined. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a TypeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +assert.throws(TypeError, function() { + dtf.formatRange(); // Not possible to poison this one +}, "no args"); + +var poison = { valueOf() { throw new Test262Error(); } }; + +assert.throws(TypeError, function() { + dtf.formatRange(undefined, poison); +}, "date/undefined"); + +assert.throws(TypeError, function() { + dtf.formatRange(poison, undefined); +}, "undefined/date"); + +assert.throws(TypeError, function() { + dtf.formatRange(poison); +}, "only one arg"); + +assert.throws(TypeError, function() { + dtf.formatRange(undefined, undefined); +}, "undefined/undefined"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js new file mode 100644 index 0000000000..1ddc9d49c7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js @@ -0,0 +1,35 @@ +// Copyright 2022 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Return a string if date x is greater than y. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 4. Let x be ? ToNumber(startDate). + 5. Let y be ? ToNumber(endDate). + 6. Return ? FormatDateTimeRange(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var x = new Date(); +var y = new Date(); +x.setDate(y.getDate() + 1); + +assert.sameValue("string", typeof dtf.formatRange(x, y)); +assert.sameValue("string", typeof dtf.formatRange(x, x)); +assert.sameValue("string", typeof dtf.formatRange(y, y)); +assert.sameValue("string", typeof dtf.formatRange(y, x)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js new file mode 100644 index 0000000000..756b9f8f35 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js @@ -0,0 +1,45 @@ +// Copyright (C) 2019 the V8 project authors, Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: Basic tests for the en-US output of formatRange() +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 8. Return ? FormatDateTimeRange(dtf, x, y). +locale: [en-US] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === "literal" && part.source === "shared").value; + +const date1 = new Date("2019-01-03T00:00:00"); +const date2 = new Date("2019-01-05T00:00:00"); +const date3 = new Date("2019-03-04T00:00:00"); +const date4 = new Date("2020-03-04T00:00:00"); + +let dtf = new Intl.DateTimeFormat("en-US"); +assert.sameValue(dtf.formatRange(date1, date1), "1/3/2019"); +assert.sameValue(dtf.formatRange(date1, date2), `1/3/2019${usDateRangeSeparator}1/5/2019`); +assert.sameValue(dtf.formatRange(date1, date3), `1/3/2019${usDateRangeSeparator}3/4/2019`); +assert.sameValue(dtf.formatRange(date1, date4), `1/3/2019${usDateRangeSeparator}3/4/2020`); +assert.sameValue(dtf.formatRange(date2, date3), `1/5/2019${usDateRangeSeparator}3/4/2019`); +assert.sameValue(dtf.formatRange(date2, date4), `1/5/2019${usDateRangeSeparator}3/4/2020`); +assert.sameValue(dtf.formatRange(date3, date4), `3/4/2019${usDateRangeSeparator}3/4/2020`); + +dtf = new Intl.DateTimeFormat("en-US", {year: "numeric", month: "short", day: "numeric"}); +assert.sameValue(dtf.formatRange(date1, date1), "Jan 3, 2019"); +assert.sameValue(dtf.formatRange(date1, date2), `Jan 3${usDateRangeSeparator}5, 2019`); +assert.sameValue(dtf.formatRange(date1, date3), `Jan 3${usDateRangeSeparator}Mar 4, 2019`); +assert.sameValue(dtf.formatRange(date1, date4), `Jan 3, 2019${usDateRangeSeparator}Mar 4, 2020`); +assert.sameValue(dtf.formatRange(date2, date3), `Jan 5${usDateRangeSeparator}Mar 4, 2019`); +assert.sameValue(dtf.formatRange(date2, date4), `Jan 5, 2019${usDateRangeSeparator}Mar 4, 2020`); +assert.sameValue(dtf.formatRange(date3, date4), `Mar 4, 2019${usDateRangeSeparator}Mar 4, 2020`); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js new file mode 100644 index 0000000000..781ea43d26 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js @@ -0,0 +1,42 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of fractionalSecondDigits. +features: [Intl.DateTimeFormat-fractionalSecondDigits, Intl.DateTimeFormat-formatRange] +locale: [en-US] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === "literal" && part.source === "shared").value; + +const d1 = new Date(2019, 7, 10, 1, 2, 3, 234); +const d2 = new Date(2019, 7, 10, 1, 2, 3, 567); +const d3 = new Date(2019, 7, 10, 1, 2, 13, 987); + +let dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined}); +assert.sameValue(dtf.formatRange(d1, d2), "02:03", "no fractionalSecondDigits"); +assert.sameValue(dtf.formatRange(d1, d3), `02:03${usDateRangeSeparator}02:13`, "no fractionalSecondDigits"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1}); +assert.sameValue(dtf.formatRange(d1, d2), `02:03.2${usDateRangeSeparator}02:03.5`, "1 fractionalSecondDigits round down"); +assert.sameValue(dtf.formatRange(d1, d3), `02:03.2${usDateRangeSeparator}02:13.9`, "1 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2}); +assert.sameValue(dtf.formatRange(d1, d2), `02:03.23${usDateRangeSeparator}02:03.56`, "2 fractionalSecondDigits round down"); +assert.sameValue(dtf.formatRange(d1, d3), `02:03.23${usDateRangeSeparator}02:13.98`, "2 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3}); +assert.sameValue(dtf.formatRange(d1, d2), `02:03.234${usDateRangeSeparator}02:03.567`, "3 fractionalSecondDigits round down"); +assert.sameValue(dtf.formatRange(d1, d3), `02:03.234${usDateRangeSeparator}02:13.987`, "3 fractionalSecondDigits round down"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js new file mode 100644 index 0000000000..bd1605e0ce --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js @@ -0,0 +1,16 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatRange.length. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatRange, 'length', { + value: 2, + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js new file mode 100644 index 0000000000..f3ded8535e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js @@ -0,0 +1,16 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatRange.name value and descriptor. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatRange, 'name', { + value: 'formatRange', + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js new file mode 100644 index 0000000000..e022b19320 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js @@ -0,0 +1,23 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Property type and descriptor. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +assert.sameValue( + typeof Intl.DateTimeFormat.prototype.formatRange, + 'function', + '`typeof Intl.DateTimeFormat.prototype.formatRange` is `function`' +); + +verifyProperty(Intl.DateTimeFormat.prototype, 'formatRange', { + enumerable: false, + writable: true, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js new file mode 100644 index 0000000000..985f46c993 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js @@ -0,0 +1,55 @@ +// GENERATED, DO NOT EDIT +// file: dateConstants.js +// Copyright (C) 2009 the Sputnik authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + Collection of date-centric values +defines: + - date_1899_end + - date_1900_start + - date_1969_end + - date_1970_start + - date_1999_end + - date_2000_start + - date_2099_end + - date_2100_start + - start_of_time + - end_of_time +---*/ + +var date_1899_end = -2208988800001; +var date_1900_start = -2208988800000; +var date_1969_end = -1; +var date_1970_start = 0; +var date_1999_end = 946684799999; +var date_2000_start = 946684800000; +var date_2099_end = 4102444799999; +var date_2100_start = 4102444800000; + +var start_of_time = -8.64e15; +var end_of_time = 8.64e15; + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js new file mode 100644 index 0000000000..a381435baa --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js @@ -0,0 +1,58 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: A time zone in resolvedOptions with a large offset still produces the correct string +locale: [en] +features: [Temporal, Intl.DateTimeFormat-formatRange] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDayPeriodSpace = + new Intl.DateTimeFormat("en-US", { timeStyle: "short" }) + .formatToParts(0) + .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || ""; +const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === "literal" && part.source === "shared").value; + +const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" }); + +const date1 = new Temporal.PlainDate(2021, 8, 4); +const date2 = new Temporal.PlainDate(2021, 8, 5); +const dateResult = formatter.formatRange(date1, date2); +assert.sameValue(dateResult, `8/4/2021${usDateRangeSeparator}8/5/2021`, "plain dates"); + +const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789); +const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789); +const datetimeResult = formatter.formatRange(datetime1, datetime2); +assert.sameValue( + datetimeResult, + `8/4/2021, 12:30:45${usDayPeriodSpace}AM${usDateRangeSeparator}11:30:45${usDayPeriodSpace}PM`, + "plain datetimes" +); + +const monthDay1 = new Temporal.PlainMonthDay(8, 4, "gregory"); +const monthDay2 = new Temporal.PlainMonthDay(8, 5, "gregory"); +const monthDayResult = formatter.formatRange(monthDay1, monthDay2); +assert.sameValue(monthDayResult, `8/4${usDateRangeSeparator}8/5`, "plain month-days"); + +const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789); +const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789); +const timeResult = formatter.formatRange(time1, time2); +assert.sameValue( + timeResult, + `12:30:45${usDayPeriodSpace}AM${usDateRangeSeparator}11:30:45${usDayPeriodSpace}PM`, + "plain times" +); + +const month1 = new Temporal.PlainYearMonth(2021, 8, "gregory"); +const month2 = new Temporal.PlainYearMonth(2021, 9, "gregory"); +const monthResult = formatter.formatRange(month1, month2); +assert.sameValue(monthResult, `8/2021${usDateRangeSeparator}9/2021`, "plain year-months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js new file mode 100644 index 0000000000..3eca117f82 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.formatRangeToParts +description: Temporal.ZonedDateTime is not supported directly in formatRangeToParts() +features: [Temporal] +---*/ + +const formatter = new Intl.DateTimeFormat(); + +// Check that TypeError would not be thrown for a different reason +const {timeZone, ...options} = formatter.resolvedOptions(); +const datetime1 = new Temporal.ZonedDateTime(0n, timeZone); +assert.sameValue(typeof datetime1.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds"); + +const datetime2 = new Temporal.ZonedDateTime(1_000_000_000n, timeZone); +assert.throws(TypeError, () => formatter.formatRangeToParts(datetime1, datetime2), "formatRangeToParts() does not support Temporal.ZonedDateTime"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js new file mode 100644 index 0000000000..e669dc4421 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js @@ -0,0 +1,28 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if this is not a DateTimeFormat object +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const formatRange = Intl.DateTimeFormat.prototype.formatRange; + +assert.throws(TypeError, function() { + formatRange.call({}); +}, "{}"); + +assert.throws(TypeError, function() { + formatRange.call(new Date()); +}, "new Date()"); + +assert.throws(TypeError, function() { + formatRange.call(Intl.DateTimeFormat); +}, "Intl.DateTimeFormat"); + +assert.throws(TypeError, function() { + formatRange.call(Intl.DateTimeFormat.prototype); +}, "Intl.DateTimeFormat.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js new file mode 100644 index 0000000000..970d3e3d33 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js @@ -0,0 +1,49 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if this is not Object. +info: | + Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + +features: [Intl.DateTimeFormat-formatRange, Symbol] +---*/ + +let formatRange = Intl.DateTimeFormat.prototype.formatRange; +let d1 = new Date("1997-08-22T00:00"); +let d2 = new Date("1999-06-26T00:00"); + +assert.throws(TypeError, function() { + formatRange.call(undefined, d1, d2); +}, "undefined"); + +assert.throws(TypeError, function() { + formatRange.call(null, d1, d2); +}, "null"); + +assert.throws(TypeError, function() { + formatRange.call(42, d1, d2); +}, "number"); + +assert.throws(TypeError, function() { + formatRange.call("foo", d1, d2); +}, "string"); + +assert.throws(TypeError, function() { + formatRange.call(false, d1, d2); +}, "false"); + +assert.throws(TypeError, function() { + formatRange.call(true, d1, d2); +}, "true"); + +var s = Symbol('3'); +assert.throws(TypeError, function() { + formatRange.call(s, d1, d2); +}, "symbol"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js new file mode 100644 index 0000000000..56c7156a63 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js @@ -0,0 +1,41 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + The Date constructor is not called to convert the input value. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 8. Return ? FormatDateTimeRange(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const dtf = new Intl.DateTimeFormat(); +const dateTimeString = "2017-11-10T14:09:00.000Z"; +const date = new Date(dateTimeString); +// |dateTimeString| is valid ISO-8601 style date/time string. +assert.notSameValue(date, NaN); + +// ToNumber() will try to parse the string as an integer and yield NaN, rather +// than attempting to parse it like the Date constructor would. +assert.throws(RangeError, function() { + dtf.formatRangeToParts(dateTimeString, date); +}); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, dateTimeString); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js new file mode 100644 index 0000000000..ea87893bf1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js @@ -0,0 +1,49 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatRangeToParts. +info: | + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + + TimeClip ( time ) + ... + 2. If abs(time) > 8.64 × 10^15, return NaN. + ... + +includes: [dateConstants.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const dtf = new Intl.DateTimeFormat(); +const date = Date.now(); + +// Test values near the start of the ECMAScript time range. +assert.throws(RangeError, function() { + dtf.formatRangeToParts(start_of_time - 1, date); +}); +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, start_of_time - 1); +}); +assert.sameValue(typeof dtf.formatRangeToParts(start_of_time, date), "object"); +assert.sameValue(typeof dtf.formatRangeToParts(start_of_time + 1, date), "object"); + +// Test values near the end of the ECMAScript time range. +assert.sameValue(typeof dtf.formatRangeToParts(date, end_of_time - 1), "object"); +assert.sameValue(typeof dtf.formatRangeToParts(date, end_of_time), "object"); +assert.throws(RangeError, function() { + dtf.formatRangeToParts(end_of_time + 1, date); +}); +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, end_of_time + 1); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js new file mode 100644 index 0000000000..df97c735a1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js @@ -0,0 +1,56 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// Copyright (C) 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + TimeClip applies ToInteger on its input value. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + + TimeClip ( time ) + ... + 3. Let clippedTime be ! ToInteger(time). + 4. If clippedTime is -0, set clippedTime to +0. + 5. Return clippedTime. +features: [Intl.DateTimeFormat-formatRange] +---*/ + +function* zip(a, b) { + assert.sameValue(a.length, b.length); + for (let i = 0; i < a.length; ++i) { + yield [i, a[i], b[i]]; + } +} + +function compare(actual, expected, message) { + for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) { + assert.sameValue(actualEntry.type, expectedEntry.type, `${message}: type for entry ${i}`); + assert.sameValue(actualEntry.value, expectedEntry.value, `${message}: value for entry ${i}`); + assert.sameValue(actualEntry.source, expectedEntry.source, `${message}: source for entry ${i}`); + } +} + +// Switch to a time format instead of using DateTimeFormat's default date-only format. +const dtf = new Intl.DateTimeFormat(undefined, { + hour: "numeric", minute: "numeric", second: "numeric" +}); +const date = Date.now(); +const expected = dtf.formatRangeToParts(0, date); + +compare(dtf.formatRangeToParts(-0.9, date), expected, "formatRangeToParts(-0.9)"); +compare(dtf.formatRangeToParts(-0.5, date), expected, "formatRangeToParts(-0.5)"); +compare(dtf.formatRangeToParts(-0.1, date), expected, "formatRangeToParts(-0.1)"); +compare(dtf.formatRangeToParts(-Number.MIN_VALUE, date), expected, "formatRangeToParts(-Number.MIN_VALUE)"); +compare(dtf.formatRangeToParts(-0, date), expected, "formatRangeToParts(-0)"); +compare(dtf.formatRangeToParts(+0, date), expected, "formatRangeToParts(+0)"); +compare(dtf.formatRangeToParts(Number.MIN_VALUE, date), expected, "formatRangeToParts(Number.MIN_VALUE)"); +compare(dtf.formatRangeToParts(0.1, date), expected, "formatRangeToParts(0.1)"); +compare(dtf.formatRangeToParts(0.5, date), expected, "formatRangeToParts(0.5)"); +compare(dtf.formatRangeToParts(0.9, date), expected, "formatRangeToParts(0.9)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js new file mode 100644 index 0000000000..d38b20da1c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js @@ -0,0 +1,56 @@ +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Return abrupt completions from ToNumber(date) +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). +features: [Symbol,Intl.DateTimeFormat-formatRange] +---*/ + +const date = Date.now(); + +const objectValueOf = { + valueOf: function() { + throw new Test262Error(); + } +}; + +const objectToString = { + toString: function() { + throw new Test262Error(); + } +}; + +const dtf = new Intl.DateTimeFormat(["pt-BR"]); + +assert.throws(Test262Error, function() { + dtf.formatRangeToParts(objectValueOf, date); +}, "valueOf start"); + +assert.throws(Test262Error, function() { + dtf.formatRangeToParts(date, objectValueOf); +}, "valueOf end"); + +assert.throws(Test262Error, function() { + dtf.formatRangeToParts(objectToString, date); +}, "toString start"); + +assert.throws(Test262Error, function() { + dtf.formatRangeToParts(date, objectToString); +}, "toString end"); + +const s = Symbol('1'); +assert.throws(TypeError, function() { + dtf.formatRangeToParts(s, date); +}, "symbol start"); + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(date, s); +}, "symbol end"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js new file mode 100644 index 0000000000..840c232f07 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + Tests that the Intl.DateTimeFormat.prototype.formatRangeToParts function meets the + requirements for built-in objects defined by the ECMAScript Language + Specification. +includes: [isConstructor.js] +features: [Reflect.construct,Intl.DateTimeFormat-formatRange] +---*/ + +const formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts; + +assert.sameValue(Object.prototype.toString.call(formatRangeToParts), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(formatRangeToParts), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(formatRangeToParts), Function.prototype); + +assert.sameValue(formatRangeToParts.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(formatRangeToParts), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js new file mode 100644 index 0000000000..9074bc63f0 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js @@ -0,0 +1,71 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to an Infinity value +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a RangeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 7. If x is greater than y, throw a RangeError exception. + 8. Return ? FormatDateTimeRangeToParts(dtf, x, y). + + FormatDateTimeRangeToParts ( dateTimeFormat, x, y ) + + 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + + TimeClip ( time ) + 1. If time is not finite, return NaN. + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var date = new Date(); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(Infinity, date); +}, "+Infinity/date"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(-Infinity, date); +}, "-Infinity/date"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, Infinity); +}, "date/+Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, -Infinity); +}, "date/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(Infinity, Infinity); +}, "+Infinity/+Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(-Infinity, -Infinity); +}, "-Infinity/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(Infinity, -Infinity); +}, "+Infinity/-Infinity"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(-Infinity, Infinity); +}, "-Infinity/+Infinity"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js new file mode 100644 index 0000000000..a96a0f3d70 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js @@ -0,0 +1,49 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to Nan +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a RangeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + 7. If x is greater than y, throw a RangeError exception. + 8. Return ? FormatDateTimeRangeToParts(dtf, x, y). + + FormatDateTimeRangeToParts ( dateTimeFormat, x, y ) + + 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. + +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var date = new Date(); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(NaN, date); +}, "NaN/date"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(date, NaN); +}, "date/NaN"); + +assert.throws(RangeError, function() { + dtf.formatRangeToParts(NaN, NaN); +}, "NaN/NaN"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js new file mode 100644 index 0000000000..551a1fddcc --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js @@ -0,0 +1,78 @@ +// Copyright 2021 Google Inc. All rights reserved. +// Copyright 2021 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: > + When startDate is equal to endDate, the output should be an Array of objects with the + same value for the `type` and `value` fields as in the Array returned by + Intl.DateTimeFormat.prototype.formatToParts. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 4. Let x be ? ToNumber(startDate). + 5. Let y be ? ToNumber(endDate). + 6. Return ? FormatDateTimeRange(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + + 13. If dateFieldsPracticallyEqual is true, then + a. Let pattern be dateTimeFormat.[[Pattern]]. + b. Let patternParts be PartitionPattern(pattern). + c. Let result be ? FormatDateTimePattern(dateTimeFormat, patternParts, tm1). + d. For each r in result do + i. Set r.[[Source]] to "shared". + e. Return result. + +features: [Intl.DateTimeFormat-formatRange] +locale: [en-US] +---*/ + +function* zip(a, b) { + assert.sameValue(a.length, b.length); + for (let i = 0; i < a.length; ++i) { + yield [i, a[i], b[i]]; + } +} + +function compare(actual, expected) { + for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) { + assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`); + assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`); + } +} + +{ + const date = new Date(2019, 7, 10, 1, 2, 3, 234); + + let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" }); + compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with date options"); + + dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" }); + compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with time options"); + + dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" }); + compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with date-time options"); + + dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }); + compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with dateStyle/timeStyle"); +} +{ + const date1 = new Date(2019, 7, 10, 1, 2, 3, 234); + const date2 = new Date(2019, 7, 10, 1, 2, 3, 235); + + let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" }); + compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with date options"); + + dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" }); + compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with time options"); + + dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" }); + compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with date-time options"); + + dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }); + compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with dateStyle/timeStyle"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js new file mode 100644 index 0000000000..5c3e06dd10 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js @@ -0,0 +1,43 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if startDate or endDate are undefined. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception. + 4. If startDate is undefined or endDate is undefined, throw a TypeError exception. + 5. Let x be ? ToNumber(startDate). + 6. Let y be ? ToNumber(endDate). + +features: [Intl.DateTimeFormat-formatRange] +---*/ +var dtf = new Intl.DateTimeFormat(); + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(); // Not possible to poison this one +}, "no args"); + +var poison = { valueOf() { throw new Test262Error(); } }; + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(undefined, poison); +}, "date/undefined"); + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(poison, undefined); +}, "undefined/date"); + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(poison); +}, "only one arg"); + +assert.throws(TypeError, function() { + dtf.formatRangeToParts(undefined, undefined); +}, "undefined/undefined"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js new file mode 100644 index 0000000000..ae527481cd --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js @@ -0,0 +1,33 @@ +// Copyright 2022 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Return an object if date x is greater than y. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 4. Let x be ? ToNumber(startDate). + 5. Let y be ? ToNumber(endDate). + 6. Return ? FormatDateTimeRangeToParts(dtf, x, y). + + PartitionDateTimeRangePattern ( dateTimeFormat, x, y ) + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. Let y be TimeClip(y). + 4. If y is NaN, throw a RangeError exception. +features: [Intl.DateTimeFormat-formatRange] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var x = new Date(); +var y = new Date(); +x.setDate(y.getDate() + 1); + +assert.sameValue("object", typeof dtf.formatRangeToParts(x, y)); +assert.sameValue("object", typeof dtf.formatRangeToParts(x, x)); +assert.sameValue("object", typeof dtf.formatRangeToParts(y, y)); +assert.sameValue("object", typeof dtf.formatRangeToParts(y, x)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js new file mode 100644 index 0000000000..559d8eb2fd --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js @@ -0,0 +1,208 @@ +// Copyright (C) 2019 the V8 project authors, Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimerangepattern +description: Basic tests for the en-US output of formatRangeToParts() +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 8. Return ? FormatDateTimeRange(dtf, x, y). +locale: [en-US] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === "literal" && part.source === "shared").value; + +function* zip(a, b) { + assert.sameValue(a.length, b.length); + for (let i = 0; i < a.length; ++i) { + yield [i, a[i], b[i]]; + } +} + +function compare(actual, expected) { + for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) { + assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`); + assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`); + assert.sameValue(actualEntry.source, expectedEntry.source, `source for entry ${i}`); + } +} + +const date1 = new Date("2019-01-03T00:00:00"); +const date2 = new Date("2019-01-05T00:00:00"); +const date3 = new Date("2019-03-04T00:00:00"); +const date4 = new Date("2020-03-04T00:00:00"); + +let dtf = new Intl.DateTimeFormat("en-US"); +compare(dtf.formatRangeToParts(date1, date1), [ + { type: "month", value: "1", source: "shared" }, + { type: "literal", value: "/", source: "shared" }, + { type: "day", value: "3", source: "shared" }, + { type: "literal", value: "/", source: "shared" }, + { type: "year", value: "2019", source: "shared" }, +]); +compare(dtf.formatRangeToParts(date1, date2), [ + { type: "month", value: "1", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "1", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "5", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2019", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date1, date3), [ + { type: "month", value: "1", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "3", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2019", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date1, date4), [ + { type: "month", value: "1", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "3", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date2, date3), [ + { type: "month", value: "1", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "5", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "3", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2019", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date2, date4), [ + { type: "month", value: "1", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "5", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "3", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date3, date4), [ + { type: "month", value: "3", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "4", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "3", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); + +dtf = new Intl.DateTimeFormat("en-US", {year: "numeric", month: "short", day: "numeric"}); +compare(dtf.formatRangeToParts(date1, date1), [ + { type: "month", value: "Jan", source: "shared" }, + { type: "literal", value: " ", source: "shared" }, + { type: "day", value: "3", source: "shared" }, + { type: "literal", value: ", ", source: "shared" }, + { type: "year", value: "2019", source: "shared" }, +]); +compare(dtf.formatRangeToParts(date1, date2), [ + { type: "month", value: "Jan", source: "shared" }, + { type: "literal", value: " ", source: "shared" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "day", value: "5", source: "endRange" }, + { type: "literal", value: ", ", source: "shared" }, + { type: "year", value: "2019", source: "shared" }, +]); +compare(dtf.formatRangeToParts(date1, date3), [ + { type: "month", value: "Jan", source: "startRange" }, + { type: "literal", value: " ", source: "startRange" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "Mar", source: "endRange" }, + { type: "literal", value: " ", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: ", ", source: "shared" }, + { type: "year", value: "2019", source: "shared" }, +]); +compare(dtf.formatRangeToParts(date1, date4), [ + { type: "month", value: "Jan", source: "startRange" }, + { type: "literal", value: " ", source: "startRange" }, + { type: "day", value: "3", source: "startRange" }, + { type: "literal", value: ", ", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "Mar", source: "endRange" }, + { type: "literal", value: " ", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: ", ", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date2, date3), [ + { type: "month", value: "Jan", source: "startRange" }, + { type: "literal", value: " ", source: "startRange" }, + { type: "day", value: "5", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "Mar", source: "endRange" }, + { type: "literal", value: " ", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: ", ", source: "shared" }, + { type: "year", value: "2019", source: "shared" }, +]); +compare(dtf.formatRangeToParts(date2, date4), [ + { type: "month", value: "Jan", source: "startRange" }, + { type: "literal", value: " ", source: "startRange" }, + { type: "day", value: "5", source: "startRange" }, + { type: "literal", value: ", ", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "Mar", source: "endRange" }, + { type: "literal", value: " ", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: ", ", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); +compare(dtf.formatRangeToParts(date3, date4), [ + { type: "month", value: "Mar", source: "startRange" }, + { type: "literal", value: " ", source: "startRange" }, + { type: "day", value: "4", source: "startRange" }, + { type: "literal", value: ", ", source: "startRange" }, + { type: "year", value: "2019", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "Mar", source: "endRange" }, + { type: "literal", value: " ", source: "endRange" }, + { type: "day", value: "4", source: "endRange" }, + { type: "literal", value: ", ", source: "endRange" }, + { type: "year", value: "2020", source: "endRange" }, +]); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js new file mode 100644 index 0000000000..0840f80d25 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js @@ -0,0 +1,160 @@ +// Copyright 2020 Google Inc, Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of fractionalSecondDigits. +features: [Intl.DateTimeFormat-fractionalSecondDigits, Intl.DateTimeFormat-formatRange] +locale: [en-US] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === "literal" && part.source === "shared").value; + +function* zip(a, b) { + assert.sameValue(a.length, b.length); + for (let i = 0; i < a.length; ++i) { + yield [i, a[i], b[i]]; + } +} + +function compare(actual, expected) { + for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) { + assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`); + assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`); + assert.sameValue(actualEntry.source, expectedEntry.source, `source for entry ${i}`); + } +} + +const d1 = new Date(2019, 7, 10, 1, 2, 3, 234); +const d2 = new Date(2019, 7, 10, 1, 2, 3, 567); +const d3 = new Date(2019, 7, 10, 1, 2, 13, 987); + +assert.throws(RangeError, () => { + new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 0}); + }, "fractionalSecondDigits 0 should throw RangeError for out of range"); + +assert.throws(RangeError, () => { + new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 4}); + }, "fractionalSecondDigits 4 should throw RangeError for out of range"); + +let dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined}); + +compare(dtf.formatRangeToParts(d1, d2), [ + { type: "minute", value: "02", source: "shared" }, + { type: "literal", value: ":", source: "shared" }, + { type: "second", value: "03", source: "shared" } +]); + +compare(dtf.formatRangeToParts(d1, d3), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "13", source: "endRange" } +]); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1}); + +compare(dtf.formatRangeToParts(d1, d2), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "2", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "03", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "5", source: "endRange" } +]); + +compare(dtf.formatRangeToParts(d1, d3), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "2", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "13", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "9", source: "endRange" } +]); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2}); + +compare(dtf.formatRangeToParts(d1, d2), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "23", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "03", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "56", source: "endRange" } +]); + +compare(dtf.formatRangeToParts(d1, d3), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "23", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "13", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "98", source: "endRange" } +]); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3}); + +compare(dtf.formatRangeToParts(d1, d2), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "234", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "03", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "567", source: "endRange" } +]); + +compare(dtf.formatRangeToParts(d1, d3), [ + { type: "minute", value: "02", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "03", source: "startRange" }, + { type: "literal", value: ".", source: "startRange" }, + { type: "fractionalSecond", value: "234", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "minute", value: "02", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "13", source: "endRange" }, + { type: "literal", value: ".", source: "endRange" }, + { type: "fractionalSecond", value: "987", source: "endRange" } +]); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js new file mode 100644 index 0000000000..0a41d864dc --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js @@ -0,0 +1,16 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatRangeToParts.length. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatRangeToParts, 'length', { + value: 2, + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js new file mode 100644 index 0000000000..0d857a6e83 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js @@ -0,0 +1,16 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatRangeToParts.name value and descriptor. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatRangeToParts, 'name', { + value: 'formatRangeToParts', + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js new file mode 100644 index 0000000000..f36730d122 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js @@ -0,0 +1,40 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks the DateTimeFormat choose different patterns based + on calendar. +includes: [testIntl.js] +features: [Intl.DateTimeFormat-formatRange] +locale: [en] +---*/ + +let calendars = allCalendars(); +let date1 = new Date(2017, 3, 12); +let date2 = new Date(); + +// serialize parts to a string by considering only the type and literal. +function serializeTypesAndLiteral(parts) { + let types = parts.map(part => { + if (part.type == "literal") { + return `${part.type}(${part.value})`; + } + return part.type; + }); + return types.join(":"); +} + +let df = new Intl.DateTimeFormat("en"); +let base = serializeTypesAndLiteral(df.formatRangeToParts(date1, date2)); + +const foundDifferentPattern = calendars.some(function(calendar) { + let cdf = new Intl.DateTimeFormat("en-u-ca-" + calendar); + return base != serializeTypesAndLiteral(cdf.formatRangeToParts(date1, date2)); +}); + +// Expect at least some calendar use different pattern. +assert.sameValue(foundDifferentPattern, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js new file mode 100644 index 0000000000..edd871b1ad --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js @@ -0,0 +1,23 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// Copyright 2019 Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Property type and descriptor. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-formatRange] +---*/ + +assert.sameValue( + typeof Intl.DateTimeFormat.prototype.formatRangeToParts, + 'function', + '`typeof Intl.DateTimeFormat.prototype.formatRangeToParts` is `function`' +); + +verifyProperty(Intl.DateTimeFormat.prototype, 'formatRangeToParts', { + enumerable: false, + writable: true, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js new file mode 100644 index 0000000000..99241dca55 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js @@ -0,0 +1,384 @@ +// GENERATED, DO NOT EDIT +// file: dateConstants.js +// Copyright (C) 2009 the Sputnik authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + Collection of date-centric values +defines: + - date_1899_end + - date_1900_start + - date_1969_end + - date_1970_start + - date_1999_end + - date_2000_start + - date_2099_end + - date_2100_start + - start_of_time + - end_of_time +---*/ + +var date_1899_end = -2208988800001; +var date_1900_start = -2208988800000; +var date_1969_end = -1; +var date_1970_start = 0; +var date_1999_end = 946684799999; +var date_2000_start = 946684800000; +var date_2099_end = 4102444799999; +var date_2100_start = 4102444800000; + +var start_of_time = -8.64e15; +var end_of_time = 8.64e15; + +// file: deepEqual.js +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: > + Compare two values structurally +defines: [assert.deepEqual] +---*/ + +assert.deepEqual = function(actual, expected, message) { + var format = assert.deepEqual.format; + assert( + assert.deepEqual._compare(actual, expected), + `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}` + ); +}; + +assert.deepEqual.format = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return `[Function${value.name ? `: ${value.name}` : ''}]`; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return `Date "${value.toISOString()}"`; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + let usage = seen.map.get(value); + if (usage) { + usage.used = true; + return `[Ref: #${usage.id}]`; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (typeof Map !== "undefined" && value instanceof Map) { + return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`; + } + let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`; + default: + return typeof value; + } +}; + +assert.deepEqual._compare = (function () { + var EQUAL = 1; + var NOT_EQUAL = -1; + var UNKNOWN = 0; + + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + function isOptional(value) { + return value === undefined + || value === null; + } + + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + function isValueOfEquatable(value) { + return value instanceof Date; + } + + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + function getCache(cache, left, right) { + var otherCache; + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js new file mode 100644 index 0000000000..ec34d8e9a9 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js @@ -0,0 +1,117 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: A time zone in resolvedOptions with a large offset still produces the correct string +locale: [en] +includes: [deepEqual.js] +features: [Temporal, Intl.DateTimeFormat-formatRange] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDayPeriodSpace = + new Intl.DateTimeFormat('en-US', { timeStyle: 'short' }) + .formatToParts(0) + .find((part, i, parts) => part.type === 'literal' && parts[i + 1].type === 'dayPeriod')?.value || ''; +const usDateRangeSeparator = new Intl.DateTimeFormat('en-US', { dateStyle: 'short' }) + .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000) + .find((part) => part.type === 'literal' && part.source === 'shared').value; + +const formatter = new Intl.DateTimeFormat('en-US', { timeZone: 'Pacific/Apia' }); + +const date1 = new Temporal.PlainDate(2021, 8, 4); +const date2 = new Temporal.PlainDate(2021, 8, 5); +const dateResult = formatter.formatRangeToParts(date1, date2); +assert.deepEqual(dateResult, [ + { type: "month", value: "8", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "4", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2021", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "8", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "5", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2021", source: "endRange" }, +], "plain dates"); + +const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789); +const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789); +const datetimeResult = formatter.formatRangeToParts(datetime1, datetime2); +assert.deepEqual(datetimeResult, [ + { type: "month", value: "8", source: "shared" }, + { type: "literal", value: "/", source: "shared" }, + { type: "day", value: "4", source: "shared" }, + { type: "literal", value: "/", source: "shared" }, + { type: "year", value: "2021", source: "shared" }, + { type: "literal", value: ", ", source: "shared" }, + { type: "hour", value: "12", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "minute", value: "30", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "45", source: "startRange" }, + { type: "literal", value: usDayPeriodSpace, source: "startRange" }, + { type: "dayPeriod", value: "AM", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "hour", value: "11", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "minute", value: "30", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "45", source: "endRange" }, + { type: "literal", value: usDayPeriodSpace, source: "endRange" }, + { type: "dayPeriod", value: "PM", source: "endRange" }, +], "plain datetimes"); + +const monthDay1 = new Temporal.PlainMonthDay(8, 4, "gregory"); +const monthDay2 = new Temporal.PlainMonthDay(8, 5, "gregory"); +const monthDayResult = formatter.formatRangeToParts(monthDay1, monthDay2); +assert.deepEqual(monthDayResult, [ + { type: "month", value: "8", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "day", value: "4", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "8", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "day", value: "5", source: "endRange" }, +], "plain month-days"); + +const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789); +const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789); +const timeResult = formatter.formatRangeToParts(time1, time2); +assert.deepEqual(timeResult, [ + { type: "hour", value: "12", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "minute", value: "30", source: "startRange" }, + { type: "literal", value: ":", source: "startRange" }, + { type: "second", value: "45", source: "startRange" }, + { type: "literal", value: usDayPeriodSpace, source: "startRange" }, + { type: "dayPeriod", value: "AM", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "hour", value: "11", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "minute", value: "30", source: "endRange" }, + { type: "literal", value: ":", source: "endRange" }, + { type: "second", value: "45", source: "endRange" }, + { type: "literal", value: usDayPeriodSpace, source: "endRange" }, + { type: "dayPeriod", value: "PM", source: "endRange" }, +], "plain times"); + +const month1 = new Temporal.PlainYearMonth(2021, 8, "gregory"); +const month2 = new Temporal.PlainYearMonth(2021, 9, "gregory"); +const monthResult = formatter.formatRangeToParts(month1, month2); +assert.deepEqual(monthResult, [ + { type: "month", value: "8", source: "startRange" }, + { type: "literal", value: "/", source: "startRange" }, + { type: "year", value: "2021", source: "startRange" }, + { type: "literal", value: usDateRangeSeparator, source: "shared" }, + { type: "month", value: "9", source: "endRange" }, + { type: "literal", value: "/", source: "endRange" }, + { type: "year", value: "2021", source: "endRange" }, +], "plain year-months"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js new file mode 100644 index 0000000000..edc0263d10 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.formatRange +description: Temporal.ZonedDateTime is not supported directly in formatRange() +features: [Temporal] +---*/ + +const formatter = new Intl.DateTimeFormat(); + +// Check that TypeError would not be thrown for a different reason +const {timeZone, ...options} = formatter.resolvedOptions(); +const datetime1 = new Temporal.ZonedDateTime(0n, timeZone); +assert.sameValue(typeof datetime1.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds"); + +const datetime2 = new Temporal.ZonedDateTime(1_000_000_000n, timeZone); +assert.throws(TypeError, () => formatter.formatRange(datetime1, datetime2), "formatRange() does not support Temporal.ZonedDateTime"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js new file mode 100644 index 0000000000..21f29b4541 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js @@ -0,0 +1,28 @@ +// Copyright 2019 Igalia, S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if this is not a DateTimeFormat object +features: [Intl.DateTimeFormat-formatRange] +---*/ + +const formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts; + +assert.throws(TypeError, function() { + formatRangeToParts.call({}); +}, "{}"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(new Date()); +}, "new Date()"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(Intl.DateTimeFormat); +}, "Intl.DateTimeFormat"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(Intl.DateTimeFormat.prototype); +}, "Intl.DateTimeFormat.prototype"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js new file mode 100644 index 0000000000..7fe4599531 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js @@ -0,0 +1,49 @@ +// Copyright 2019 Google, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if this is not Object. +info: | + Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate ) + + 1. Let dtf be this value. + 2. If Type(dtf) is not Object, throw a TypeError exception. + +features: [Intl.DateTimeFormat-formatRange, Symbol] +---*/ + +let formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts; +let d1 = new Date("1997-08-22T00:00"); +let d2 = new Date("1999-06-26T00:00"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(undefined, d1, d2); +}, "undefined"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(null, d1, d2); +}, "null"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(42, d1, d2); +}, "number"); + +assert.throws(TypeError, function() { + formatRangeToParts.call("foo", d1, d2); +}, "string"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(false, d1, d2); +}, "false"); + +assert.throws(TypeError, function() { + formatRangeToParts.call(true, d1, d2); +}, "true"); + +var s = Symbol('3'); +assert.throws(TypeError, function() { + formatRangeToParts.call(s, d1, d2); +}, "symbol"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js new file mode 100644 index 0000000000..9c63ee3e52 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js @@ -0,0 +1,38 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + The Date constructor is not called to convert the input value. +info: > + 12.4.4 Intl.DateTimeFormat.prototype.formatToParts ( date ) + + ... + 4. If date is undefined, then + ... + 5. Else, + a. Let x be ? ToNumber(date). + 5. Return ? FormatDateTimeToParts(dtf, x). + + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. ... +---*/ + +var dtf = new Intl.DateTimeFormat(); + +var dateTimeString = "2017-11-10T14:09:00.000Z"; + +// |dateTimeString| is valid ISO-8601 style date/time string. +assert.notSameValue(new Date(dateTimeString), NaN); + +// Ensure string input values are not converted to time values by calling the +// Date constructor. +assert.throws(RangeError, function() { + dtf.formatToParts(dateTimeString); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js new file mode 100644 index 0000000000..071c07ed45 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js @@ -0,0 +1,35 @@ +// Copyright 2016 Leonardo Balter. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to an Infinity value +info: | + Intl.DateTimeFormat.prototype.formatToParts ([ date ]) + + 4. If _date_ is not provided or is *undefined*, then + a. Let _x_ be *%Date_now%*(). + 5. Else, + a. Let _x_ be ? ToNumber(_date_). + 6. Return ? FormatDateTimeToParts(_dtf_, _x_). + + FormatDateTimeToParts(dateTimeFormat, x) + + 1. Let _parts_ be ? PartitionDateTimePattern(_dateTimeFormat_, _x_). + + PartitionDateTimePattern (dateTimeFormat, x) + + 1. If _x_ is not a finite Number, throw a *RangeError* exception. +---*/ + +var dtf = new Intl.DateTimeFormat(["pt-BR"]); + +assert.throws(RangeError, function() { + dtf.formatToParts(Infinity); +}, "+Infinity"); + +assert.throws(RangeError, function() { + dtf.formatToParts(-Infinity); +}, "-Infinity"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js new file mode 100644 index 0000000000..ab062734e0 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js @@ -0,0 +1,35 @@ +// Copyright 2016 Leonardo Balter. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Throws a RangeError if date arg is cast to NaN +info: | + Intl.DateTimeFormat.prototype.formatToParts ([ date ]) + + 4. If _date_ is not provided or is *undefined*, then + a. Let _x_ be *%Date_now%*(). + 5. Else, + a. Let _x_ be ? ToNumber(_date_). + 6. Return ? FormatDateTimeToParts(_dtf_, _x_). + + FormatDateTimeToParts(dateTimeFormat, x) + + 1. Let _parts_ be ? PartitionDateTimePattern(_dateTimeFormat_, _x_). + + PartitionDateTimePattern (dateTimeFormat, x) + + 1. If _x_ is not a finite Number, throw a *RangeError* exception. +---*/ + +var dtf = new Intl.DateTimeFormat(["pt-BR"]); + +assert.throws(RangeError, function() { + dtf.formatToParts(NaN); +}); + +assert.throws(RangeError, function() { + dtf.formatToParts("lol"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js new file mode 100644 index 0000000000..ef2e24f43d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js @@ -0,0 +1,108 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of dayPeriod, long format. +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const long = new Intl.DateTimeFormat('en', { dayPeriod: 'long' }); + +function assertParts(parts, expected, message) { + assert.sameValue(parts.length, 1, `length should be 1, ${message}`); + assert.sameValue(parts[0].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`); +} + +assertParts(long.formatToParts(d0000), 'at night', '00:00, long format'); +assertParts(long.formatToParts(d0100), 'at night', '01:00, long format'); +assertParts(long.formatToParts(d0200), 'at night', '02:00, long format'); +assertParts(long.formatToParts(d0300), 'at night', '03:00, long format'); +assertParts(long.formatToParts(d0400), 'at night', '04:00, long format'); +assertParts(long.formatToParts(d0500), 'at night', '05:00, long format'); +assertParts(long.formatToParts(d0600), 'in the morning', '06:00, long format'); +assertParts(long.formatToParts(d0700), 'in the morning', '07:00, long format'); +assertParts(long.formatToParts(d0800), 'in the morning', '08:00, long format'); +assertParts(long.formatToParts(d0900), 'in the morning', '09:00, long format'); +assertParts(long.formatToParts(d1000), 'in the morning', '10:00, long format'); +assertParts(long.formatToParts(d1100), 'in the morning', '11:00, long format'); +assertParts(long.formatToParts(d1200), 'noon', '12:00, long format'); +assertParts(long.formatToParts(d1300), 'in the afternoon', '13:00, long format'); +assertParts(long.formatToParts(d1400), 'in the afternoon', '14:00, long format'); +assertParts(long.formatToParts(d1500), 'in the afternoon', '15:00, long format'); +assertParts(long.formatToParts(d1600), 'in the afternoon', '16:00, long format'); +assertParts(long.formatToParts(d1700), 'in the afternoon', '17:00, long format'); +assertParts(long.formatToParts(d1800), 'in the evening', '18:00, long format'); +assertParts(long.formatToParts(d1900), 'in the evening', '19:00, long format'); +assertParts(long.formatToParts(d2000), 'in the evening', '20:00, long format'); +assertParts(long.formatToParts(d2100), 'at night', '21:00, long format'); +assertParts(long.formatToParts(d2200), 'at night', '22:00, long format'); +assertParts(long.formatToParts(d2300), 'at night', '23:00, long format'); + +const longNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'long', + hour: 'numeric' +}); + +function assertPartsNumeric(parts, hour, expected, message) { + assert.sameValue(parts.length, 3, `length should be 3, ${message}`); + assert.sameValue(parts[0].value, hour, `hour part value. ${message}`); + assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`); + assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`); + assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`); + assert.sameValue(parts[2].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`); +} + +assertPartsNumeric(longNumeric.formatToParts(d0000), '12', 'at night', '00:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0100), '1', 'at night', '01:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0200), '2', 'at night', '02:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0300), '3', 'at night', '03:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0400), '4', 'at night', '04:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0500), '5', 'at night', '05:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1200), '12', 'noon', '12:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d2100), '9', 'at night', '21:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d2200), '10', 'at night', '22:00, long-numeric'); +assertPartsNumeric(longNumeric.formatToParts(d2300), '11', 'at night', '23:00, long-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js new file mode 100644 index 0000000000..7bcebc2537 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js @@ -0,0 +1,108 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of dayPeriod, narrow format. +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const narrow = new Intl.DateTimeFormat('en', { dayPeriod: 'narrow' }); + +function assertParts(parts, expected, message) { + assert.sameValue(parts.length, 1, `length should be 1, ${message}`); + assert.sameValue(parts[0].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`); +} + +assertParts(narrow.formatToParts(d0000), 'at night', '00:00, narrow format'); +assertParts(narrow.formatToParts(d0100), 'at night', '01:00, narrow format'); +assertParts(narrow.formatToParts(d0200), 'at night', '02:00, narrow format'); +assertParts(narrow.formatToParts(d0300), 'at night', '03:00, narrow format'); +assertParts(narrow.formatToParts(d0400), 'at night', '04:00, narrow format'); +assertParts(narrow.formatToParts(d0500), 'at night', '05:00, narrow format'); +assertParts(narrow.formatToParts(d0600), 'in the morning', '06:00, narrow format'); +assertParts(narrow.formatToParts(d0700), 'in the morning', '07:00, narrow format'); +assertParts(narrow.formatToParts(d0800), 'in the morning', '08:00, narrow format'); +assertParts(narrow.formatToParts(d0900), 'in the morning', '09:00, narrow format'); +assertParts(narrow.formatToParts(d1000), 'in the morning', '10:00, narrow format'); +assertParts(narrow.formatToParts(d1100), 'in the morning', '11:00, narrow format'); +assertParts(narrow.formatToParts(d1200), 'n', '12:00, narrow format'); +assertParts(narrow.formatToParts(d1300), 'in the afternoon', '13:00, narrow format'); +assertParts(narrow.formatToParts(d1400), 'in the afternoon', '14:00, narrow format'); +assertParts(narrow.formatToParts(d1500), 'in the afternoon', '15:00, narrow format'); +assertParts(narrow.formatToParts(d1600), 'in the afternoon', '16:00, narrow format'); +assertParts(narrow.formatToParts(d1700), 'in the afternoon', '17:00, narrow format'); +assertParts(narrow.formatToParts(d1800), 'in the evening', '18:00, narrow format'); +assertParts(narrow.formatToParts(d1900), 'in the evening', '19:00, narrow format'); +assertParts(narrow.formatToParts(d2000), 'in the evening', '20:00, narrow format'); +assertParts(narrow.formatToParts(d2100), 'at night', '21:00, narrow format'); +assertParts(narrow.formatToParts(d2200), 'at night', '22:00, narrow format'); +assertParts(narrow.formatToParts(d2300), 'at night', '23:00, narrow format'); + +const narrowNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'narrow', + hour: 'numeric' +}); + +function assertPartsNumeric(parts, hour, expected, message) { + assert.sameValue(parts.length, 3, `length should be 3, ${message}`); + assert.sameValue(parts[0].value, hour, `hour part value. ${message}`); + assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`); + assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`); + assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`); + assert.sameValue(parts[2].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`); +} + +assertPartsNumeric(narrowNumeric.formatToParts(d0000), '12', 'at night', '00:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0100), '1', 'at night', '01:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0200), '2', 'at night', '02:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0300), '3', 'at night', '03:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0400), '4', 'at night', '04:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0500), '5', 'at night', '05:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1200), '12', 'n', '12:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d2100), '9', 'at night', '21:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d2200), '10', 'at night', '22:00, narrow-numeric'); +assertPartsNumeric(narrowNumeric.formatToParts(d2300), '11', 'at night', '23:00, narrow-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js new file mode 100644 index 0000000000..66ec863b3d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js @@ -0,0 +1,108 @@ +// Copyright 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of dayPeriod, short format. +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0); +const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0); +const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0); +const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0); +const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0); +const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0); +const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0); +const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0); +const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0); +const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0); +const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0); +const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0); +const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0); +const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0); +const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0); +const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0); +const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0); +const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0); +const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0); +const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0); +const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0); +const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0); +const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0); +const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0); + +const short = new Intl.DateTimeFormat('en', { dayPeriod: 'short' }); + +function assertParts(parts, expected, message) { + assert.sameValue(parts.length, 1, `length should be 1, ${message}`); + assert.sameValue(parts[0].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`); +} + +assertParts(short.formatToParts(d0000), 'at night', '00:00, short format'); +assertParts(short.formatToParts(d0100), 'at night', '01:00, short format'); +assertParts(short.formatToParts(d0200), 'at night', '02:00, short format'); +assertParts(short.formatToParts(d0300), 'at night', '03:00, short format'); +assertParts(short.formatToParts(d0400), 'at night', '04:00, short format'); +assertParts(short.formatToParts(d0500), 'at night', '05:00, short format'); +assertParts(short.formatToParts(d0600), 'in the morning', '06:00, short format'); +assertParts(short.formatToParts(d0700), 'in the morning', '07:00, short format'); +assertParts(short.formatToParts(d0800), 'in the morning', '08:00, short format'); +assertParts(short.formatToParts(d0900), 'in the morning', '09:00, short format'); +assertParts(short.formatToParts(d1000), 'in the morning', '10:00, short format'); +assertParts(short.formatToParts(d1100), 'in the morning', '11:00, short format'); +assertParts(short.formatToParts(d1200), 'noon', '12:00, short format'); +assertParts(short.formatToParts(d1300), 'in the afternoon', '13:00, short format'); +assertParts(short.formatToParts(d1400), 'in the afternoon', '14:00, short format'); +assertParts(short.formatToParts(d1500), 'in the afternoon', '15:00, short format'); +assertParts(short.formatToParts(d1600), 'in the afternoon', '16:00, short format'); +assertParts(short.formatToParts(d1700), 'in the afternoon', '17:00, short format'); +assertParts(short.formatToParts(d1800), 'in the evening', '18:00, short format'); +assertParts(short.formatToParts(d1900), 'in the evening', '19:00, short format'); +assertParts(short.formatToParts(d2000), 'in the evening', '20:00, short format'); +assertParts(short.formatToParts(d2100), 'at night', '21:00, short format'); +assertParts(short.formatToParts(d2200), 'at night', '22:00, short format'); +assertParts(short.formatToParts(d2300), 'at night', '23:00, short format'); + +const shortNumeric = new Intl.DateTimeFormat('en', { + dayPeriod: 'short', + hour: 'numeric' +}); + +function assertPartsNumeric(parts, hour, expected, message) { + assert.sameValue(parts.length, 3, `length should be 3, ${message}`); + assert.sameValue(parts[0].value, hour, `hour part value. ${message}`); + assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`); + assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`); + assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`); + assert.sameValue(parts[2].value, expected, `expected part value. ${message}`); + assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`); +} + +assertPartsNumeric(shortNumeric.formatToParts(d0000), '12', 'at night', '00:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0100), '1', 'at night', '01:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0200), '2', 'at night', '02:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0300), '3', 'at night', '03:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0400), '4', 'at night', '04:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0500), '5', 'at night', '05:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1200), '12', 'noon', '12:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d2100), '9', 'at night', '21:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d2200), '10', 'at night', '22:00, short-numeric'); +assertPartsNumeric(shortNumeric.formatToParts(d2300), '11', 'at night', '23:00, short-numeric'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js new file mode 100644 index 0000000000..a0045ba71c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js @@ -0,0 +1,21 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Property type and descriptor. +includes: [propertyHelper.js] +---*/ + +assert.sameValue( + typeof Intl.DateTimeFormat.prototype.formatToParts, + 'function', + '`typeof Intl.DateTimeFormat.prototype.formatToParts` is `function`' +); + +verifyProperty(Intl.DateTimeFormat.prototype, "formatToParts", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js new file mode 100644 index 0000000000..543dfb2274 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js @@ -0,0 +1,69 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: Checks basic handling of fractionalSecondDigits. +features: [Intl.DateTimeFormat-fractionalSecondDigits] +locale: [en-US] +---*/ + +const d1 = new Date(2019, 7, 10, 1, 2, 3, 234); +const d2 = new Date(2019, 7, 10, 1, 2, 3, 567); + +function assertParts(parts, minute, second, fractionalSecond, message) { + if (fractionalSecond === null) { + assert.sameValue(parts.length, 3, `length should be 3, ${message}`); + } else { + assert.sameValue(parts.length, 5, `length should be 5, ${message}`); + } + assert.sameValue(parts[0].value, minute, `minute part value. ${message}`); + assert.sameValue(parts[0].type, 'minute', `minute part type. ${message}`); + assert.sameValue(parts[1].value, ':', `literal part value. ${message}`); + assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`); + assert.sameValue(parts[2].value, second, `second part value. ${message}`); + assert.sameValue(parts[2].type, 'second', `second part type. ${message}`); + if (fractionalSecond !== null) { + assert.sameValue(parts[3].value, '.', `literal part value. ${message}`); + assert.sameValue(parts[3].type, 'literal', `literal part type. ${message}`); + assert.sameValue(parts[4].value, fractionalSecond, `fractionalSecond part value. ${message}`); + assert.sameValue(parts[4].type, 'fractionalSecond', `fractionalSecond part type. ${message}`); + } +} + +assert.throws(RangeError, () => { + new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 0}); +}, "fractionalSecondDigits 0 should throw RangeError for out of range"); + +assert.throws(RangeError, () => { + new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 4}); +}, "fractionalSecondDigits 4 should throw RangeError for out of range"); + +let dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric"}); +assertParts(dtf.formatToParts(d1), "02", "03", null, "no fractionalSecondDigits round down"); +assertParts(dtf.formatToParts(d2), "02", "03", null, "no fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined}); +assertParts(dtf.formatToParts(d1), "02", "03", null, "no fractionalSecondDigits round down"); +assertParts(dtf.formatToParts(d2), "02", "03", null, "no fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1}); +assertParts(dtf.formatToParts(d1), "02", "03", "2", "1 fractionalSecondDigits round down"); +assertParts(dtf.formatToParts(d2), "02", "03", "5", "1 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2}); +assertParts(dtf.formatToParts(d1), "02", "03", "23", "2 fractionalSecondDigits round down"); +assertParts(dtf.formatToParts(d2), "02", "03", "56", "2 fractionalSecondDigits round down"); + +dtf = new Intl.DateTimeFormat( + 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3}); +assertParts(dtf.formatToParts(d1), "02", "03", "234", "3 fractionalSecondDigits round down"); +assertParts(dtf.formatToParts(d2), "02", "03", "567", "3 fractionalSecondDigits round down"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js new file mode 100644 index 0000000000..cc596ada97 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js @@ -0,0 +1,15 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatToParts.length. +includes: [propertyHelper.js] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatToParts, 'length', { + value: 1, + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js new file mode 100644 index 0000000000..b42b917232 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js @@ -0,0 +1,76 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Tests for existance and behavior of Intl.DateTimeFormat.prototype.formatToParts +features: [Array.prototype.includes] +---*/ + +function reduce(parts) { + return parts.map(part => part.value).join(''); +} + +function compareFTPtoFormat(locales, options, value) { + const dtf = new Intl.DateTimeFormat(locales, options); + assert.sameValue( + dtf.format(value), + reduce(dtf.formatToParts(value)), + `Expected the same value for value ${value}, + locales: ${locales} and options: ${options}` + ); +} + +compareFTPtoFormat(); +compareFTPtoFormat('pl'); +compareFTPtoFormat(['pl']); +compareFTPtoFormat([]); +compareFTPtoFormat(['de'], undefined, 0); +compareFTPtoFormat(['de'], undefined, -10); +compareFTPtoFormat(['de'], undefined, 25324234235); +compareFTPtoFormat(['de'], { + day: '2-digit' +}, Date.now()); +compareFTPtoFormat(['de'], { + day: 'numeric', + year: '2-digit' +}, Date.now()); +compareFTPtoFormat(['ar'], { + month: 'numeric', + day: 'numeric', + year: '2-digit' +}, Date.now()); + +const actualPartTypes = new Intl.DateTimeFormat('en-us', { + weekday: 'long', + era: 'long', + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: true, + timeZone: 'UTC', + timeZoneName: 'long' +}).formatToParts(Date.UTC(2012, 11, 17, 3, 0, 42)) + .map(part => part.type); + +const legalPartTypes = [ + 'weekday', + 'era', + 'year', + 'month', + 'day', + 'hour', + 'minute', + 'second', + 'literal', + 'dayPeriod', + 'timeZoneName', +]; + +actualPartTypes.forEach(function(type) { + assert(legalPartTypes.includes(type), `${type} is not a legal type`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js new file mode 100644 index 0000000000..92b4805ee9 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js @@ -0,0 +1,15 @@ +// Copyright 2016 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Intl.DateTimeFormat.prototype.formatToParts.name value and descriptor. +includes: [propertyHelper.js] +---*/ +verifyProperty(Intl.DateTimeFormat.prototype.formatToParts, 'name', { + value: 'formatToParts', + enumerable: false, + writable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js new file mode 100644 index 0000000000..1ebffa9a77 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js @@ -0,0 +1,30 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: > + Tests that formatted hour and minute are correct for offset time zones. +---*/ +let date = new Date('1995-12-17T03:24:56Z'); +let tests = { + '+0301': {hour: "6", minute: "25"}, + '+1412': {hour: "5", minute: "36"}, + '+02': {hour: "5", minute: "24"}, + '+13:49': {hour: "5", minute: "13"}, + '-07:56': {hour: "7", minute: "28"}, + '-12': {hour: "3", minute: "24"}, + '−0914': {hour: "6", minute: "10"}, + '−10:03': {hour: "5", minute: "21"}, + '−0509': {hour: "10", minute: "15"}, +}; +Object.entries(tests).forEach(([timeZone, expected]) => { + let df = new Intl.DateTimeFormat("en", + {timeZone, timeStyle: "short"}); + let res = df.formatToParts(date); + let hour = res.filter((t) => t.type === "hour")[0].value + let minute = res.filter((t) => t.type === "minute")[0].value + assert.sameValue(hour, expected.hour, `hour in ${timeZone} time zone:`); + assert.sameValue(minute, expected.minute, `minute in ${timeZone} time zone:`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js new file mode 100644 index 0000000000..7a9a753983 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js @@ -0,0 +1,38 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Checks the DateTimeFormat choose different patterns based + on calendar. +includes: [testIntl.js] +locale: [en] +---*/ + +let calendars = allCalendars(); +let date = new Date(); + +// serialize parts to a string by considering only the type and literal. +function serializeTypesAndLiteral(parts) { + let types = parts.map(part => { + if (part.type == "literal") { + return `${part.type}(${part.value})`; + } + return part.type; + }); + return types.join(":"); +} + +let df = new Intl.DateTimeFormat("en"); +let base = serializeTypesAndLiteral(df.formatToParts(date)); + +const foundDifferentPattern = calendars.some(function(calendar) { + let cdf = new Intl.DateTimeFormat("en-u-ca-" + calendar); + return base != serializeTypesAndLiteral(cdf.formatToParts(date)); +}); + +// Expect at least some calendar use different pattern. +assert.sameValue(foundDifferentPattern, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js new file mode 100644 index 0000000000..1033404e00 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js @@ -0,0 +1,35 @@ +// Copyright 2019 Google Inc, Igalia S.L. All rights reserved. +// Copyright 2020 Apple Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: > + Checks the output of 'relatedYear' and 'yearName' type, and + the choice of pattern based on calendar. +locale: [zh-u-ca-chinese] +---*/ + +const df = new Intl.DateTimeFormat("zh-u-ca-chinese", {year: "numeric"}); +const date = new Date(2019, 5, 1); +const actual = df.formatToParts(date); + +const expected = [ + {type: "relatedYear", value: "2019"}, + {type: "yearName", value: "己亥"}, + {type: "literal", value: "年"}, +]; + +assert.sameValue(Array.isArray(actual), true, 'actual is Array'); + +if (actual.length <= 2) { + expected.shift(); // removes the relatedYear +} + +actual.forEach(({ type, value }, i) => { + const { type: eType, value: eValue } = expected[i]; + assert.sameValue(type, eType, `actual[${i}].type should be ${eType}`); + assert.sameValue(value, eValue, `actual[${i}].value should be ${eValue}`); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js new file mode 100644 index 0000000000..92aae9e730 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js @@ -0,0 +1,23 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: > + Checks the output of 'relatedYear' and 'yearName' type, and + the choose of pattern base on calendar. +locale: [en-u-ca-chinese] +---*/ + +let df = new Intl.DateTimeFormat("en-u-ca-chinese", {year: "numeric"}); +let parts = df.formatToParts(new Date()); +var relatedYearCount = 0; +var yearNameCount = 0; +parts.forEach(function(part) { + relatedYearCount += (part.type == "relatedYear") ? 1 : 0; + yearNameCount += (part.type == "yearName") ? 1 : 0; +}); +assert.sameValue(relatedYearCount > 0, true); +assert.sameValue(yearNameCount > 0, true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js new file mode 100644 index 0000000000..b8141a3776 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js @@ -0,0 +1,44 @@ +// Copyright 2016 Leonardo Balter. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Return abrupt completions from ToNumber(date) +info: | + Intl.DateTimeFormat.prototype.formatToParts ([ date ]) + + 4. If _date_ is not provided or is *undefined*, then + a. Let _x_ be *%Date_now%*(). + 5. Else, + a. Let _x_ be ? ToNumber(_date_). +features: [Symbol] +---*/ + +var obj1 = { + valueOf: function() { + throw new Test262Error(); + } +}; + +var obj2 = { + toString: function() { + throw new Test262Error(); + } +}; + +var dtf = new Intl.DateTimeFormat(["pt-BR"]); + +assert.throws(Test262Error, function() { + dtf.formatToParts(obj1); +}, "valueOf"); + +assert.throws(Test262Error, function() { + dtf.formatToParts(obj2); +}, "toString"); + +var s = Symbol('1'); +assert.throws(TypeError, function() { + dtf.formatToParts(s); +}, "symbol"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js new file mode 100644 index 0000000000..cce6b3c2a3 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js @@ -0,0 +1,360 @@ +// GENERATED, DO NOT EDIT +// file: dateConstants.js +// Copyright (C) 2009 the Sputnik authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + Collection of date-centric values +defines: + - date_1899_end + - date_1900_start + - date_1969_end + - date_1970_start + - date_1999_end + - date_2000_start + - date_2099_end + - date_2100_start + - start_of_time + - end_of_time +---*/ + +var date_1899_end = -2208988800001; +var date_1900_start = -2208988800000; +var date_1969_end = -1; +var date_1970_start = 0; +var date_1999_end = 946684799999; +var date_2000_start = 946684800000; +var date_2099_end = 4102444799999; +var date_2100_start = 4102444800000; + +var start_of_time = -8.64e15; +var end_of_time = 8.64e15; + +// file: deepEqual.js +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: > + Compare two values structurally +defines: [assert.deepEqual] +---*/ + +assert.deepEqual = function(actual, expected, message) { + var format = assert.deepEqual.format; + assert( + assert.deepEqual._compare(actual, expected), + `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}` + ); +}; + +assert.deepEqual.format = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return `[Function${value.name ? `: ${value.name}` : ''}]`; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return `Date "${value.toISOString()}"`; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + let usage = seen.map.get(value); + if (usage) { + usage.used = true; + return `[Ref: #${usage.id}]`; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (typeof Map !== "undefined" && value instanceof Map) { + return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`; + } + let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`; + default: + return typeof value; + } +}; + +assert.deepEqual._compare = (function () { + var EQUAL = 1; + var NOT_EQUAL = -1; + var UNKNOWN = 0; + + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + function isOptional(value) { + return value === undefined + || value === null; + } + + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + function isValueOfEquatable(value) { + return value instanceof Date; + } + + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + function getCache(cache, left, right) { + var otherCache; + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js new file mode 100644 index 0000000000..f764995862 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js @@ -0,0 +1,107 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.formatToParts +description: A time zone in resolvedOptions with a large offset still produces the correct string +locale: [en] +includes: [deepEqual.js] +features: [Temporal] +---*/ + +// Tolerate implementation variance by expecting consistency without being prescriptive. +// TODO: can we change tests to be less reliant on CLDR formats while still testing that +// Temporal and Intl are behaving as expected? +const usDayPeriodSpace = + new Intl.DateTimeFormat("en-US", { timeStyle: "short" }) + .formatToParts(0) + .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || ""; + +const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" }); + +const date = new Temporal.PlainDate(2021, 8, 4); +const dateResult = formatter.formatToParts(date); +assert.deepEqual(dateResult, [ + { type: "month", value: "8" }, + { type: "literal", value: "/" }, + { type: "day", value: "4" }, + { type: "literal", value: "/" }, + { type: "year", value: "2021" }, +], "plain date"); + +const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789); +const datetimeResult1 = formatter.formatToParts(datetime1); +assert.deepEqual(datetimeResult1, [ + { type: "month", value: "8" }, + { type: "literal", value: "/" }, + { type: "day", value: "4" }, + { type: "literal", value: "/" }, + { type: "year", value: "2021" }, + { type: "literal", value: ", " }, + { type: "hour", value: "12" }, + { type: "literal", value: ":" }, + { type: "minute", value: "30" }, + { type: "literal", value: ":" }, + { type: "second", value: "45" }, + { type: "literal", value: usDayPeriodSpace }, + { type: "dayPeriod", value: "AM" }, +], "plain datetime close to beginning of day"); +const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789); +const datetimeResult2 = formatter.formatToParts(datetime2); +assert.deepEqual(datetimeResult2, [ + { type: "month", value: "8" }, + { type: "literal", value: "/" }, + { type: "day", value: "4" }, + { type: "literal", value: "/" }, + { type: "year", value: "2021" }, + { type: "literal", value: ", " }, + { type: "hour", value: "11" }, + { type: "literal", value: ":" }, + { type: "minute", value: "30" }, + { type: "literal", value: ":" }, + { type: "second", value: "45" }, + { type: "literal", value: usDayPeriodSpace }, + { type: "dayPeriod", value: "PM" }, +], "plain datetime close to end of day"); + +const monthDay = new Temporal.PlainMonthDay(8, 4, "gregory"); +const monthDayResult = formatter.formatToParts(monthDay); +assert.deepEqual(monthDayResult, [ + { type: "month", value: "8" }, + { type: "literal", value: "/" }, + { type: "day", value: "4" }, +], "plain month-day"); + +const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789); +const timeResult1 = formatter.formatToParts(time1); +assert.deepEqual(timeResult1, [ + { type: "hour", value: "12" }, + { type: "literal", value: ":" }, + { type: "minute", value: "30" }, + { type: "literal", value: ":" }, + { type: "second", value: "45" }, + { type: "literal", value: usDayPeriodSpace }, + { type: "dayPeriod", value: "AM" }, +], "plain time close to beginning of day"); +const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789); +const timeResult2 = formatter.formatToParts(time2); +assert.deepEqual(timeResult2, [ + { type: "hour", value: "11" }, + { type: "literal", value: ":" }, + { type: "minute", value: "30" }, + { type: "literal", value: ":" }, + { type: "second", value: "45" }, + { type: "literal", value: usDayPeriodSpace }, + { type: "dayPeriod", value: "PM" }, +], "plain time close to end of day"); + +const month = new Temporal.PlainYearMonth(2021, 8, "gregory"); +const monthResult = formatter.formatToParts(month); +assert.deepEqual(monthResult, [ + { type: "month", value: "8" }, + { type: "literal", value: "/" }, + { type: "year", value: "2021" }, +], "plain year-month"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js new file mode 100644 index 0000000000..ec7438195b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.formatToParts +description: Temporal.ZonedDateTime is not supported directly in formatToParts() +features: [Temporal] +---*/ + +const formatter = new Intl.DateTimeFormat(); + +// Check that TypeError would not be thrown for a different reason +const {timeZone, ...options} = formatter.resolvedOptions(); +const datetime = new Temporal.ZonedDateTime(0n, timeZone); +assert.sameValue(typeof datetime.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds"); + +assert.throws(TypeError, () => formatter.formatToParts(datetime), "formatToParts() does not support Temporal.ZonedDateTime"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js new file mode 100644 index 0000000000..18dae83a16 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js @@ -0,0 +1,19 @@ +// Copyright 2016 Leonardo Balter. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: > + Throws a TypeError if this is not a DateTimeFormat object +---*/ + +var formatToParts = Intl.DateTimeFormat.prototype.formatToParts; + +assert.throws(TypeError, function() { + formatToParts.call({}); +}, "{}"); + +assert.throws(TypeError, function() { + formatToParts.call(new Date()); +}, "new Date()"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js new file mode 100644 index 0000000000..0837bfb1ca --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js @@ -0,0 +1,40 @@ +// Copyright 2016 Leonardo Balter. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +description: Throws a TypeError if this is not Object +features: [Symbol] +---*/ + +var formatToParts = Intl.DateTimeFormat.prototype.formatToParts; + +assert.throws(TypeError, function() { + formatToParts.call(undefined); +}, "undefined"); + +assert.throws(TypeError, function() { + formatToParts.call(null); +}, "null"); + +assert.throws(TypeError, function() { + formatToParts.call(42); +}, "number"); + +assert.throws(TypeError, function() { + formatToParts.call("foo"); +}, "string"); + +assert.throws(TypeError, function() { + formatToParts.call(false); +}, "false"); + +assert.throws(TypeError, function() { + formatToParts.call(true); +}, "true"); + +var s = Symbol('1'); +assert.throws(TypeError, function() { + formatToParts.call(s); +}, "symbol"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js new file mode 100644 index 0000000000..61599ebbc1 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatToParts. +info: > + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. If x is NaN, throw a RangeError exception. + 3. ... + + 20.3.1.15 TimeClip ( time ) + ... + 2. If abs(time) > 8.64 × 10^15, return NaN. + ... + +includes: [dateConstants.js] +---*/ + +var dtf = new Intl.DateTimeFormat(); + +// Test values near the start of the ECMAScript time range. +assert.throws(RangeError, function() { + dtf.formatToParts(start_of_time - 1); +}); +assert.sameValue(typeof dtf.formatToParts(start_of_time), "object"); +assert.sameValue(typeof dtf.formatToParts(start_of_time + 1), "object"); + +// Test values near the end of the ECMAScript time range. +assert.sameValue(typeof dtf.formatToParts(end_of_time - 1), "object"); +assert.sameValue(typeof dtf.formatToParts(end_of_time), "object"); +assert.throws(RangeError, function() { + dtf.formatToParts(end_of_time + 1); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js new file mode 100644 index 0000000000..576b08ca92 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js @@ -0,0 +1,43 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-partitiondatetimepattern +description: | + TimeClip applies ToInteger on its input value. +info: > + 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x ) + + 1. Let x be TimeClip(x). + 2. ... + + 20.3.1.15 TimeClip ( time ) + ... + 3. Let clippedTime be ! ToInteger(time). + 4. If clippedTime is -0, set clippedTime to +0. + 5. Return clippedTime. +---*/ + +// Switch to a time format instead of using DateTimeFormat's default date-only format. +var dtf = new Intl.DateTimeFormat(undefined, { + hour: "numeric", minute: "numeric", second: "numeric" +}); + +function formatAsString(dtf, time) { + return dtf.formatToParts(time).map(part => part.value).join(""); +} + +var expected = formatAsString(dtf, 0); + +assert.sameValue(formatAsString(dtf, -0.9), expected, "formatToParts(-0.9)"); +assert.sameValue(formatAsString(dtf, -0.5), expected, "formatToParts(-0.5)"); +assert.sameValue(formatAsString(dtf, -0.1), expected, "formatToParts(-0.1)"); +assert.sameValue(formatAsString(dtf, -Number.MIN_VALUE), expected, "formatToParts(-Number.MIN_VALUE)"); +assert.sameValue(formatAsString(dtf, -0), expected, "formatToParts(-0)"); +assert.sameValue(formatAsString(dtf, +0), expected, "formatToParts(+0)"); +assert.sameValue(formatAsString(dtf, Number.MIN_VALUE), expected, "formatToParts(Number.MIN_VALUE)"); +assert.sameValue(formatAsString(dtf, 0.1), expected, "formatToParts(0.1)"); +assert.sameValue(formatAsString(dtf, 0.5), expected, "formatToParts(0.5)"); +assert.sameValue(formatAsString(dtf, 0.9), expected, "formatToParts(0.9)"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js new file mode 100644 index 0000000000..711e47059a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.2.1 +description: > + Tests that Intl.DateTimeFormat.prototype has the required + attributes. +author: Norbert Lindenberg +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat, "prototype", { + writable: false, + enumerable: false, + configurable: false, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js new file mode 100644 index 0000000000..4ca918bb63 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js @@ -0,0 +1,53 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.3.3 +description: > + Tests that the object returned by + Intl.DateTimeFormat.prototype.resolvedOptions has the right + properties. +author: Norbert Lindenberg +includes: [testIntl.js, propertyHelper.js] +---*/ + +var actual = new Intl.DateTimeFormat().resolvedOptions(); + +var actual2 = new Intl.DateTimeFormat().resolvedOptions(); +assert.notSameValue(actual2, actual, "resolvedOptions returned the same object twice."); + +var calendars = allCalendars(); + +// this assumes the default values where the specification provides them +assert(isCanonicalizedStructurallyValidLanguageTag(actual.locale), + "Invalid locale: " + actual.locale); +assert.notSameValue(calendars.indexOf(actual.calendar), -1, + "Invalid calendar: " + actual.calendar); +assert(isValidNumberingSystem(actual.numberingSystem), + "Invalid numbering system: " + actual.numberingSystem); +assert(isCanonicalizedStructurallyValidTimeZoneName(actual.timeZone), + "Invalid time zone: " + actual.timeZone); +assert.notSameValue(["2-digit", "numeric"].indexOf(actual.year), -1, + "Invalid year: " + actual.year); +assert.notSameValue(["2-digit", "numeric", "narrow", "short", "long"].indexOf(actual.month), -1, + "Invalid month: " + actual.month); +assert.notSameValue(["2-digit", "numeric"].indexOf(actual.day), -1, + "Invalid day: " + actual.day); + +var dataPropertyDesc = { writable: true, enumerable: true, configurable: true }; +verifyProperty(actual, "locale", dataPropertyDesc); +verifyProperty(actual, "calendar", dataPropertyDesc); +verifyProperty(actual, "numberingSystem", dataPropertyDesc); +verifyProperty(actual, "timeZone", dataPropertyDesc); +verifyProperty(actual, "weekday", undefined); +verifyProperty(actual, "era", undefined); +verifyProperty(actual, "year", dataPropertyDesc); +verifyProperty(actual, "month", dataPropertyDesc); +verifyProperty(actual, "day", dataPropertyDesc); +verifyProperty(actual, "hour", undefined); +verifyProperty(actual, "minute", undefined); +verifyProperty(actual, "second", undefined); +verifyProperty(actual, "timeZoneName", undefined); +verifyProperty(actual, "hour12", undefined); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js new file mode 100644 index 0000000000..643376e7e2 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js @@ -0,0 +1,30 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.3.3_L15 +description: > + Tests that Intl.DateTimeFormat.prototype.resolvedOptions meets + the requirements for built-in objects defined by the introduction + of chapter 17 of the ECMAScript Language Specification. +author: Norbert Lindenberg +includes: [isConstructor.js] +features: [Reflect.construct] +---*/ + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype.resolvedOptions), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(Intl.DateTimeFormat.prototype.resolvedOptions), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.prototype.resolvedOptions), Function.prototype); + +assert.sameValue(Intl.DateTimeFormat.prototype.resolvedOptions.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(Intl.DateTimeFormat.prototype.resolvedOptions), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js new file mode 100644 index 0000000000..ebab7d4ad9 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js @@ -0,0 +1,93 @@ +// Copyright 2019 Mozilla Corporation, Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions properly + reflect hourCycle settings when using dateStyle. + Note: "properly reflect hourCycle settings when using dateStyle", in this context, means "if dateStyle but not timeStyle is set, both hourCycle and hour12 will be *undefined*". This is because the CreateDateTimeFormat AO resets [[HourCycle]] to *undefined* if [[Hour]] is *undefined*, and if dateStyle but not timeStyle is set, [[HourCycle]] is set to *undefined*. +info: | + 11.3.7 Intl.DateTimeFormat.prototype.resolvedOptions() + ... + 5. For each row of Table 6, except the header row, in table order, do + a. Let p be the Property value of the current row. + b. If p is "hour12", then + i. Let hc be dtf.[[HourCycle]]. + ii. If hc is "h11" or "h12", let v be true. + iii. Else if, hc is "h23" or "h24", let v be false. + iv. Else, let v be undefined. + c. Else, + i. Let v be the value of dtf's internal slot whose name is the Internal Slot value of the current row. + d. If the Internal Slot value of the current row is an Internal Slot value in Table 7, then + i. If dtf.[[DateStyle]] is not undefined or dtf.[[TimeStyle]] is not undefined, then + 1. Let v be undefined. + e. If v is not undefined, then + i. Perform ! CreateDataPropertyOrThrow(options, p, v). + + 11.1.2 CreateDateTimeFormat( newTarget, locales, options, required, defaults) + ... + 45. If dateTimeFormat.[[Hour]] is undefined, then + + a. Set dateTimeFormat.[[HourCycle]] to undefined. +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + +const hcValues = ["h11", "h12", "h23", "h24"]; +const hour12Values = ["h11", "h12"]; + +for (const dateStyle of ["full", "long", "medium", "short"]) { + assert.sameValue(new Intl.DateTimeFormat([], { dateStyle }).resolvedOptions().dateStyle, + dateStyle, + `Should support dateStyle=${dateStyle}`); + + /* Values passed via unicode extension key set to *undefined* */ + + for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, { + dateStyle, + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, undefined); + assert.sameValue(resolvedOptions.hour12, undefined); + } + + /* Values passed via options set to *undefined**/ + + for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat("en-US", { + dateStyle, + hourCycle: hcValue + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, undefined); + assert.sameValue(resolvedOptions.hour12, undefined); + } + + let resolvedOptions = new Intl.DateTimeFormat("en-US-u-hc-h12", { + dateStyle, + hourCycle: "h23" + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, undefined); + assert.sameValue(resolvedOptions.hour12, undefined); + + resolvedOptions = new Intl.DateTimeFormat("fr", { + dateStyle, + hour12: true, + hourCycle: "h23" + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, undefined); + assert.sameValue(resolvedOptions.hour12, undefined); + + resolvedOptions = new Intl.DateTimeFormat("fr-u-hc-h24", { + dateStyle, + hour12: true, + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, undefined); + assert.sameValue(resolvedOptions.hour12, undefined); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js new file mode 100644 index 0000000000..9063e045a6 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js @@ -0,0 +1,47 @@ +// Copyright 2019 Google Inc., 2023 Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions properly + reflect hourCycle settings. +info: | + 11.3.7 Intl.DateTimeFormat.prototype.resolvedOptions() + + 11.1.2 CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults ) + 23. Let dataLocaleData be localeData.[[]]. + 24. If hour12 is true, then + a. Let hc be dataLocaleData.[[hourCycle12]]. + 25. Else if hour12 is false, then + a. Let hc be dataLocaleData.[[hourCycle24]]. + 26. Else, + a. Assert: hour12 is undefined. + b. Let hc be r.[[hc]]. + c. If hc is null, set hc to dataLocaleData.[[hourCycle]]. + 27. Set dateTimeFormat.[[HourCycle]] to hc. + +locale: [en, fr, it, ja, zh, ko, ar, hi, en-u-hc-h24] +---*/ + +let locales = ["en", "fr", "it", "ja", "ja-u-hc-h11", "zh", "ko", "ar", "hi", "en-u-hc-h24"]; + +locales.forEach(function(locale) { + let hcDefault = new Intl.DateTimeFormat(locale, { hour: "numeric" }).resolvedOptions().hourCycle; + if (hcDefault === "h11" || hcDefault === "h12") { + assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: true }).resolvedOptions().hourCycle, hcDefault); + + // no locale has "h24" as a default. see https://github.com/tc39/ecma402/pull/758#issue-1622377292 + assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: false }).resolvedOptions().hourCycle, "h23"); + } + + // however, "h24" can be set via locale extension. + if (hcDefault === "h23" || hcDefault === "h24") { + assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: false }).resolvedOptions().hourCycle, hcDefault); + } + + let hcHour12 = new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: true }).resolvedOptions().hourCycle; + assert(hcHour12 === "h11" || hcHour12 === "h12", "Expected `hourCycle`: " + hcHour12 + " to be in [\"h11\", \"h12\"]"); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js new file mode 100644 index 0000000000..e471fbdc60 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js @@ -0,0 +1,89 @@ +// Copyright 2019 Mozilla Corporation, Igalia S.L. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions properly + reflect hourCycle settings when using timeStyle. +includes: [propertyHelper.js] +features: [Intl.DateTimeFormat-datetimestyle, Array.prototype.includes] +---*/ + +const hcValues = ["h11", "h12", "h23", "h24"]; +const hour12Values = ["h11", "h12"]; +const dataPropertyDesc = { writable: true, enumerable: true, configurable: true }; + +for (const timeStyle of ["full", "long", "medium", "short"]) { + assert.sameValue(new Intl.DateTimeFormat([], { timeStyle }).resolvedOptions().timeStyle, + timeStyle, + `Should support timeStyle=${timeStyle}`); + + /* Values passed via unicode extension key work */ + + for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, { + timeStyle, + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, hcValue); + assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue)); + } + + /* Values passed via options work */ + + for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat("en-US", { + timeStyle, + hourCycle: hcValue + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, hcValue); + assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue)); + + verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc); + verifyProperty(resolvedOptions, "hour12", dataPropertyDesc); + } + + /* When both extension key and option is passed, option takes precedence */ + + let resolvedOptions = new Intl.DateTimeFormat("en-US-u-hc-h12", { + timeStyle, + hourCycle: "h23" + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, "h23"); + assert.sameValue(resolvedOptions.hour12, false); + + verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc); + verifyProperty(resolvedOptions, "hour12", dataPropertyDesc); + + /* When hour12 and hourCycle are set, hour12 takes precedence */ + + resolvedOptions = new Intl.DateTimeFormat("fr", { + timeStyle, + hour12: true, + hourCycle: "h23" + }).resolvedOptions(); + + assert(hour12Values.includes(resolvedOptions.hourCycle)); + assert.sameValue(resolvedOptions.hour12, true); + + verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc); + verifyProperty(resolvedOptions, "hour12", dataPropertyDesc); + + /* When hour12 and extension key are set, hour12 takes precedence */ + + resolvedOptions = new Intl.DateTimeFormat("fr-u-hc-h24", { + timeStyle, + hour12: true, + }).resolvedOptions(); + + assert(hour12Values.includes(resolvedOptions.hourCycle)); + assert.sameValue(resolvedOptions.hour12, true); + + verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc); + verifyProperty(resolvedOptions, "hour12", dataPropertyDesc); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js new file mode 100644 index 0000000000..c92578e3af --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js @@ -0,0 +1,102 @@ +// Copyright 2017 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions properly + reflect hourCycle settings. +info: | + 12.4.5 Intl.DateTimeFormat.prototype.resolvedOptions() + +includes: [propertyHelper.js] +features: [Array.prototype.includes] +---*/ + +/* Values passed via unicode extension key work */ + +const hcValues = ['h11', 'h12', 'h23', 'h24']; +const hour12Values = ['h11', 'h12']; + +const dataPropertyDesc = { writable: true, enumerable: true, configurable: true }; + +for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, { + hour: 'numeric' + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, hcValue); + assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue)); + + verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc); + verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc); +} + +/* Values passed via options work */ + +for (const hcValue of hcValues) { + const resolvedOptions = new Intl.DateTimeFormat(`en-US`, { + hour: 'numeric', + hourCycle: hcValue + }).resolvedOptions(); + + assert.sameValue(resolvedOptions.hourCycle, hcValue); + assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue)); + + verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc); + verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc); +} + +/* When both extension key and option is passed, option takes precedence */ + +let resolvedOptions = new Intl.DateTimeFormat(`en-US-u-hc-h12`, { + hour: 'numeric', + hourCycle: 'h23' +}).resolvedOptions(); + +assert.sameValue(resolvedOptions.hourCycle, 'h23'); +assert.sameValue(resolvedOptions.hour12, false); + +verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc); +verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc); + +/* When hour12 and hourCycle are set, hour12 takes precedence */ + +resolvedOptions = new Intl.DateTimeFormat(`fr`, { + hour: 'numeric', + hour12: true, + hourCycle: 'h23' +}).resolvedOptions(); + +assert(hour12Values.includes(resolvedOptions.hourCycle)); +assert.sameValue(resolvedOptions.hour12, true); + +verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc); +verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc); + +/* When hour12 and extension key are set, hour12 takes precedence */ + +resolvedOptions = new Intl.DateTimeFormat(`fr-u-hc-h24`, { + hour: 'numeric', + hour12: true, +}).resolvedOptions(); + +assert(hour12Values.includes(resolvedOptions.hourCycle)); +assert.sameValue(resolvedOptions.hour12, true); + +verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc); +verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc); + +/* When the hour is not in the pattern, hourCycle and hour12 are not defined. */ + +resolvedOptions = new Intl.DateTimeFormat("fr", { + hourCycle: "h12", + hour12: false, +}).resolvedOptions(); + +assert.sameValue(resolvedOptions.hour, undefined, + "Precondition: hour should not be included by default"); +assert.sameValue(resolvedOptions.hourCycle, undefined); +assert.sameValue(resolvedOptions.hour12, undefined); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js new file mode 100644 index 0000000000..7f0bf43eb6 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js @@ -0,0 +1,34 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions.length is 0. +info: | + Intl.DateTimeFormat.prototype.resolvedOptions () + + 17 ECMAScript Standard Built-in Objects: + + Every built-in function object, including constructors, has a length + property whose value is an integer. Unless otherwise specified, this + value is equal to the largest number of named arguments shown in the + subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which + are shown using the form «...name») are not included in the default + argument count. + Unless otherwise specified, the length property of a built-in function + object has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: true }. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.prototype.resolvedOptions, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js new file mode 100644 index 0000000000..33915a9338 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2016 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + Intl.DateTimeFormat.prototype.resolvedOptions.name is "resolvedOptions". +info: | + 12.4.4 Intl.DateTimeFormat.prototype.resolvedOptions () + + 17 ECMAScript Standard Built-in Objects: + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value + is a String. + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.prototype.resolvedOptions, "name", { + value: "resolvedOptions", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js new file mode 100644 index 0000000000..0e81ebb1be --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Igalia S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: > + Tests that Intl.DateTimeFormat.prototype.resolvedOptions calls + OrdinaryHasInstance instead of the instanceof operator which includes a + Symbol.hasInstance lookup and call among other things. +info: > + UnwrapDateTimeFormat ( dtf ) + 2. If dtf does not have an [[InitializedDateTimeFormat]] internal slot and + ? OrdinaryHasInstance(%DateTimeFormat%, dtf) is true, then + a. Return ? Get(dtf, %Intl%.[[FallbackSymbol]]). +---*/ + +const dtf = Object.create(Intl.DateTimeFormat.prototype); + +Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, { + get() { throw new Test262Error(); } +}); + +assert.throws(TypeError, () => dtf.resolvedOptions()); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js new file mode 100644 index 0000000000..9f89b6106c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js @@ -0,0 +1,30 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: Tests that offset time zones are correctly normalized in resolvedOptions() output. +---*/ +let validOffsetTimeZones = [ + '+03', + '+13', + '+23', + '-07', + '-14', + '-21', + '+01:03', + '+15:59', + '+22:27', + '-02:32', + '-17:01', + '-22:23', +]; +validOffsetTimeZones.forEach((timeZone) => { + let df = new Intl.DateTimeFormat(undefined, {timeZone}); + let expected = timeZone; + if (expected.length == 3) { + expected += ":00"; + } + assert.sameValue(df.resolvedOptions().timeZone, expected, timeZone); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js new file mode 100644 index 0000000000..714286e287 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js @@ -0,0 +1,35 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-createdatetimeformat +description: Tests that offset time zones are correctly normalized in resolvedOptions() output. +---*/ +let validOffsetTimeZones = { + '-00': '+00:00', + '-00:00': '+00:00', + '−00:00': '+00:00', + '+00': '+00:00', + '+0000': '+00:00', + '+0300': '+03:00', + '+03:00': '+03:00', + '+13:00': '+13:00', + '+2300': '+23:00', + '-07:00': '-07:00', + '-14': '-14:00', + '-2100': '-21:00', + '−2200': '-22:00', + '+0103': '+01:03', + '+15:59': '+15:59', + '+2227': '+22:27', + '-02:32': '-02:32', + '-1701': '-17:01', + '-22:23': '-22:23', + '−22:53': '-22:53', +}; +Object.keys(validOffsetTimeZones).forEach((timeZone) => { + let df = new Intl.DateTimeFormat(undefined, {timeZone}); + let expected = validOffsetTimeZones[timeZone]; + assert.sameValue(df.resolvedOptions().timeZone, expected, timeZone); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js new file mode 100644 index 0000000000..971ba2ac42 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js @@ -0,0 +1,38 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: Verifies the property order for the object returned by resolvedOptions(). +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +const options = new Intl.DateTimeFormat([], { + "dayPeriod": "short", + "hour": "numeric", + "minute": "numeric", +}).resolvedOptions(); + +const expected = [ + "locale", + "calendar", + "numberingSystem", + "timeZone", + "hourCycle", + "hour12", + "dayPeriod", + "hour", + "minute", +]; + +let actual = Object.getOwnPropertyNames(options); + +// Ensure all expected items are in actual and also allow other properties +// implemented in new proposals. +assert(actual.indexOf("locale") > -1, "\"locale\" is present"); +for (var i = 1; i < expected.length; i++) { + // Ensure the order as expected but allow additional new property in between + assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js new file mode 100644 index 0000000000..2fc022b0da --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js @@ -0,0 +1,36 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: Verifies the property order for the object returned by resolvedOptions(). +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + +const options = new Intl.DateTimeFormat([], { + "fractionalSecondDigits": 3, + "minute": "numeric", + "second": "numeric", +}).resolvedOptions(); + +const expected = [ + "locale", + "calendar", + "numberingSystem", + "timeZone", + "minute", + "second", + "fractionalSecondDigits", +]; + +let actual = Object.getOwnPropertyNames(options); + +// Ensure all expected items are in actual and also allow other properties +// implemented in new proposals. +assert(actual.indexOf("locale") > -1, "\"locale\" is present"); +for (var i = 1; i < expected.length; i++) { + // Ensure the order as expected but allow additional new property in between + assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js new file mode 100644 index 0000000000..2546b1b746 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js @@ -0,0 +1,42 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: Verifies the property order for the object returned by resolvedOptions(). +features: [Intl.DateTimeFormat-datetimestyle] +---*/ + +const options = new Intl.DateTimeFormat([], { + "hourCycle": "h24", + "weekday": "short", + "era": "short", + "year": "numeric", + "month": "numeric", + "day": "numeric", + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short", +}).resolvedOptions(); + +const expected = [ + "locale", + "calendar", + "numberingSystem", + "timeZone", + "hourCycle", + "hour12", +]; + +let actual = Object.getOwnPropertyNames(options); + +// Ensure all expected items are in actual and also allow other properties +// implemented in new proposals. +assert(actual.indexOf("locale") > -1, "\"locale\" is present"); +for (var i = 1; i < expected.length; i++) { + // Ensure the order as expected but allow additional new property in between + assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js new file mode 100644 index 0000000000..13b318c5e4 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js @@ -0,0 +1,50 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: Verifies the property order for the object returned by resolvedOptions(). +---*/ + +const options = new Intl.DateTimeFormat([], { + "hourCycle": "h24", + "weekday": "short", + "era": "short", + "year": "numeric", + "month": "numeric", + "day": "numeric", + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short", +}).resolvedOptions(); + +const expected = [ + "locale", + "calendar", + "numberingSystem", + "timeZone", + "hourCycle", + "hour12", + "weekday", + "era", + "year", + "month", + "day", + "hour", + "minute", + "second", + "timeZoneName", +]; + +let actual = Object.getOwnPropertyNames(options); + +// Ensure all expected items are in actual and also allow other properties +// implemented in new proposals. +assert(actual.indexOf("locale") > -1, "\"locale\" is present"); +for (var i = 1; i < expected.length; i++) { + // Ensure the order as expected but allow additional new property in between + assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js new file mode 100644 index 0000000000..b5918cfa1e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype.resolvedoptions +description: > + "resolvedOptions" property of Intl.DateTimeFormat.prototype. +info: | + Intl.DateTimeFormat.prototype.resolvedOptions () + + 7 Requirements for Standard Built-in ECMAScript Objects + + Unless specified otherwise in this document, the objects, functions, and constructors + described in this standard are subject to the generic requirements and restrictions + specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language + Specification, 9th edition, clause 17, or successor. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 has the + attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } + unless otherwise specified. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.prototype, "resolvedOptions", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js new file mode 100644 index 0000000000..95d5f4c666 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js @@ -0,0 +1,88 @@ +// Copyright 2018 André Bargull. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions +description: > + The resolved locale doesn't include a hc Unicode extension value if the + hour12 or hourCycle option is also present. +info: | + 11.1.2 CreateDateTimeFormat( dateTimeFormat, locales, options, required, defaults ) + ... + 13. Let hour12 be ? GetOption(options, "hour12", boolean, empty, undefined). + 14. Let hourCycle be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined). + 15. If hour12 is not undefined, then + a. Set hourCycle to null. + ... + + 9.2.6 ResolveLocale(availableLocales, requestedLocales, options, relevantExtensionKeys, localeData) + ... + 8. For each element key of relevantExtensionKeys in List order, do + ... + i. If options has a field [[]], then + i. Let optionsValue be options.[[]]. + ii. Assert: Type(optionsValue) is either String, Undefined, or Null. + iii. If keyLocaleData contains optionsValue, then + 1. If SameValue(optionsValue, value) is false, then + a. Let value be optionsValue. + b. Let supportedExtensionAddition be "". + ... +---*/ + +var defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale; +var defaultLocaleWithHourCycle = defaultLocale + "-u-hc-h11"; + +function assertLocale(locale, expectedLocale, options, message) { + var resolved = new Intl.DateTimeFormat(locale, { + hour: "2-digit", + hour12: options.hour12, + hourCycle: options.hourCycle, + }).resolvedOptions(); + assert.sameValue(resolved.locale, expectedLocale, message + " (With hour option.)"); + + // Also test the case when no hour option is present at all. + // The resolved options don't include hour12 and hourCycle if the date-time + // formatter doesn't include an hour option. This restriction doesn't apply + // to the hc Unicode extension value. + resolved = new Intl.DateTimeFormat(locale, { + hour12: options.hour12, + hourCycle: options.hourCycle, + }).resolvedOptions(); + assert.sameValue(resolved.locale, expectedLocale, message + " (Without hour option.)"); +} + +assertLocale(defaultLocaleWithHourCycle, defaultLocale, { + hour12: false, + hourCycle: "h23", +}, "hour12 and hourCycle options and hc Unicode extension value are present."); + +assertLocale(defaultLocaleWithHourCycle, defaultLocale, { + hour12: false, +}, "hour12 option and hc Unicode extension value are present."); + +assertLocale(defaultLocaleWithHourCycle, defaultLocale, { + hourCycle: "h23", +}, "hourCycle option and hc Unicode extension value are present."); + +assertLocale(defaultLocaleWithHourCycle, defaultLocaleWithHourCycle, { +}, "Only hc Unicode extension value is present."); + +// And make sure the hc Unicode extension doesn't get added if it's not present +// in the requested locale. +assertLocale(defaultLocale, defaultLocale, { + hour12: false, + hourCycle: "h23", +}, "hour12 and hourCycle options are present, but no hc Unicode extension value."); + +assertLocale(defaultLocale, defaultLocale, { + hour12: false, +}, "hourCycle option is present, but no hc Unicode extension value."); + +assertLocale(defaultLocale, defaultLocale, { + hourCycle: "h23", +}, "hourCycle option is present, but no hc Unicode extension value."); + +assertLocale(defaultLocale, defaultLocale, { +}, "No options are present and no hc Unicode extension value."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js new file mode 100644 index 0000000000..34db44141b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js @@ -0,0 +1,17 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-intl-datetimeformat-prototype-object +description: > + Tests that Intl.DateTimeFormat.prototype is not an object that has + been initialized as an Intl.DateTimeFormat. +author: Roozbeh Pournader +---*/ + +// test by calling a function that should fail as "this" is not an object +// initialized as an Intl.DateTimeFormat +assert.throws(TypeError, () => Intl.DateTimeFormat.prototype.format(0), + "Intl.DateTimeFormat's prototype is not an object that has been initialized as an Intl.DateTimeFormat"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js new file mode 100644 index 0000000000..4805ca2f69 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js @@ -0,0 +1,28 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.3_b +description: > + Tests that Intl.DateTimeFormat.prototype functions throw a + TypeError if called on a non-object value or an object that hasn't + been initialized as a DateTimeFormat. +author: Norbert Lindenberg +---*/ + +var functions = { + "format getter": Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get, + resolvedOptions: Intl.DateTimeFormat.prototype.resolvedOptions +}; +var invalidTargets = [undefined, null, true, 0, "DateTimeFormat", [], {}]; + +Object.getOwnPropertyNames(functions).forEach(function (functionName) { + var f = functions[functionName]; + invalidTargets.forEach(function (target) { + assert.throws(TypeError, function() { + f.call(target); + }, "Calling " + functionName + " on " + target + " was not rejected."); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js new file mode 100644 index 0000000000..69b853ad0a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype-@@tostringtag +description: > + Object.prototype.toString utilizes Intl.DateTimeFormat.prototype[@@toStringTag]. +info: | + Object.prototype.toString ( ) + + [...] + 14. Else, let builtinTag be "Object". + 15. Let tag be ? Get(O, @@toStringTag). + 16. If Type(tag) is not String, set tag to builtinTag. + 17. Return the string-concatenation of "[object ", tag, and "]". + + Intl.DateTimeFormat.prototype [ @@toStringTag ] + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +features: [Symbol.toStringTag] +---*/ + +Object.defineProperty(Intl.DateTimeFormat.prototype, Symbol.toStringTag, { + value: "test262", +}); + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object test262]"); +assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object test262]"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js new file mode 100644 index 0000000000..170562a720 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js @@ -0,0 +1,24 @@ +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype-@@tostringtag +description: > + Object.prototype.toString doesn't special-case neither Intl.DateTimeFormat instances nor its prototype. +info: | + Object.prototype.toString ( ) + + [...] + 14. Else, let builtinTag be "Object". + 15. Let tag be ? Get(O, @@toStringTag). + 16. If Type(tag) is not String, set tag to builtinTag. + 17. Return the string-concatenation of "[object ", tag, and "]". +features: [Symbol.toStringTag] +---*/ + +delete Intl.DateTimeFormat.prototype[Symbol.toStringTag]; + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object Object]"); +assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object Object]"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js new file mode 100644 index 0000000000..f8e5d3db50 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype-@@tostringtag +description: > + Object.prototype.toString utilizes Intl.DateTimeFormat.prototype[@@toStringTag]. +info: | + Object.prototype.toString ( ) + + [...] + 14. Else, let builtinTag be "Object". + 15. Let tag be ? Get(O, @@toStringTag). + 16. If Type(tag) is not String, set tag to builtinTag. + 17. Return the string-concatenation of "[object ", tag, and "]". + + Intl.DateTimeFormat.prototype [ @@toStringTag ] + + The initial value of the @@toStringTag property is the String value "Intl.DateTimeFormat". +features: [Symbol.toStringTag] +---*/ + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object Intl.DateTimeFormat]"); +assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object Intl.DateTimeFormat]"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js new file mode 100644 index 0000000000..b118adeac8 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.prototype-@@tostringtag +description: > + Property descriptor of Intl.DateTimeFormat.prototype[@@toStringTag]. +info: | + Intl.DateTimeFormat.prototype [ @@toStringTag ] + + The initial value of the @@toStringTag property is the String value "Intl.DateTimeFormat". + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. +features: [Symbol.toStringTag] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.prototype, Symbol.toStringTag, { + value: "Intl.DateTimeFormat", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js b/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js new file mode 100644 index 0000000000..6a17fc5edb --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js @@ -0,0 +1,48 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.2.3_c +description: > + Tests that Intl.DateTimeFormat provides the required date-time + format component subsets. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +var locales = ["de-DE", "en-US", "hi-IN", "id-ID", "ja-JP", "th-TH", "zh-Hans-CN", "zh-Hant-TW", "zxx"]; +var subsets = [ + {weekday: "long", year: "numeric", month: "numeric", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "long", year: "numeric", month: "numeric", day: "numeric"}, + {year: "numeric", month: "numeric", day: "numeric"}, + {year: "numeric", month: "numeric"}, + {month: "numeric", day: "numeric"}, + {hour: "numeric", minute: "numeric", second: "numeric"}, + {hour: "numeric", minute: "numeric"} +]; + +locales.forEach(function (locale) { + subsets.forEach(function (subset) { + var format = new Intl.DateTimeFormat([locale], subset); + var actual = format.resolvedOptions(); + getDateTimeComponents().forEach(function (component) { + if (actual.hasOwnProperty(component)) { + assert(subset.hasOwnProperty(component), + "Unrequested component " + component + + " added to requested subset " + JSON.stringify(subset) + + "; locale " + locale + "."); + assert.notSameValue(getDateTimeComponentValues(component).indexOf(actual[component]), -1, + "Invalid value " + actual[component] + " for date-time component " + component + "." + + " (Testing locale " + locale + "; subset " + JSON.stringify(subset) + ")"); + } else { + assert.sameValue(subset.hasOwnProperty(component), false, + "Missing component " + component + + " from requested subset " + JSON.stringify(subset) + + "; locale " + locale + "."); + } + }); + }); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/shell.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js b/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js new file mode 100644 index 0000000000..c7167676b8 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js @@ -0,0 +1,30 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.2 +description: Tests that Intl.DateTimeFormat can be subclassed. +author: Norbert Lindenberg +includes: [compareArray.js] +---*/ + +// get a date-time format and have it format an array of dates for comparison with the subclass +var locales = ["tlh", "id", "en"]; +var a = [new Date(0), Date.now(), new Date(Date.parse("1989-11-09T17:57:00Z"))]; +var referenceDateTimeFormat = new Intl.DateTimeFormat(locales); +var referenceFormatted = a.map(referenceDateTimeFormat.format); + +class MyDateTimeFormat extends Intl.DateTimeFormat { + constructor(locales, options) { + super(locales, options); + // could initialize MyDateTimeFormat properties + } + // could add methods to MyDateTimeFormat.prototype +} + +var format = new MyDateTimeFormat(locales); +var actual = a.map(format.format); +assert.compareArray(actual, referenceFormatted); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js new file mode 100644 index 0000000000..8b4e2884e7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js @@ -0,0 +1,25 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.2.2_a +description: > + Tests that Intl.DateTimeFormat has a supportedLocalesOf property, + and it works as planned. +author: Roozbeh Pournader +---*/ + +var defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale; +var notSupported = 'zxx'; // "no linguistic content" +var requestedLocales = [defaultLocale, notSupported]; + +var supportedLocales; + +assert(Intl.DateTimeFormat.hasOwnProperty('supportedLocalesOf'), "Intl.DateTimeFormat doesn't have a supportedLocalesOf property."); + +supportedLocales = Intl.DateTimeFormat.supportedLocalesOf(requestedLocales); +assert.sameValue(supportedLocales.length, 1, 'The length of supported locales list is not 1.'); + +assert.sameValue(supportedLocales[0], defaultLocale, 'The default locale is not returned in the supported list.'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js new file mode 100644 index 0000000000..5af3ea6504 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js @@ -0,0 +1,30 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.2.2_L15 +description: > + Tests that Intl.DateTimeFormat.supportedLocalesOf meets the + requirements for built-in objects defined by the introduction of + chapter 17 of the ECMAScript Language Specification. +author: Norbert Lindenberg +includes: [isConstructor.js] +features: [Reflect.construct] +---*/ + +assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.supportedLocalesOf), "[object Function]", + "The [[Class]] internal property of a built-in function must be " + + "\"Function\"."); + +assert(Object.isExtensible(Intl.DateTimeFormat.supportedLocalesOf), + "Built-in objects must be extensible."); + +assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.supportedLocalesOf), Function.prototype); + +assert.sameValue(Intl.DateTimeFormat.supportedLocalesOf.hasOwnProperty("prototype"), false, + "Built-in functions that aren't constructors must not have a prototype property."); + +assert.sameValue(isConstructor(Intl.DateTimeFormat.supportedLocalesOf), false, + "Built-in functions don't implement [[Construct]] unless explicitly specified."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js new file mode 100644 index 0000000000..cf5e2db00b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js @@ -0,0 +1,34 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.supportedlocalesof +description: > + Intl.DateTimeFormat.supportedLocalesOf.length is 1. +info: | + Intl.DateTimeFormat.supportedLocalesOf ( locales [ , options ] ) + + 17 ECMAScript Standard Built-in Objects: + + Every built-in function object, including constructors, has a length + property whose value is an integer. Unless otherwise specified, this + value is equal to the largest number of named arguments shown in the + subclause headings for the function description. Optional parameters + (which are indicated with brackets: [ ]) or rest parameters (which + are shown using the form «...name») are not included in the default + argument count. + Unless otherwise specified, the length property of a built-in function + object has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: true }. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.supportedLocalesOf, "length", { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js new file mode 100644 index 0000000000..ca0654027b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2016 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.DateTimeFormat.supportedLocalesOf +description: > + Intl.DateTimeFormat.supportedLocalesOf.name is "supportedLocalesOf". +info: | + 12.3.2 Intl.DateTimeFormat.supportedLocalesOf (locales [ , options ]) + + 17 ECMAScript Standard Built-in Objects: + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value + is a String. + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat.supportedLocalesOf, "name", { + value: "supportedLocalesOf", + writable: false, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js new file mode 100644 index 0000000000..d5e93a5be4 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl.datetimeformat.supportedlocalesof +description: > + "supportedLocalesOf" property of Intl.DateTimeFormat. +info: | + Intl.DateTimeFormat.supportedLocalesOf ( locales [ , options ] ) + + 7 Requirements for Standard Built-in ECMAScript Objects + + Unless specified otherwise in this document, the objects, functions, and constructors + described in this standard are subject to the generic requirements and restrictions + specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language + Specification, 9th edition, clause 17, or successor. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 has the + attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } + unless otherwise specified. + +includes: [propertyHelper.js] +---*/ + +verifyProperty(Intl.DateTimeFormat, "supportedLocalesOf", { + writable: true, + enumerable: false, + configurable: true, +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js new file mode 100644 index 0000000000..eda1477282 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js @@ -0,0 +1,24 @@ +// GENERATED, DO NOT EDIT +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js new file mode 100644 index 0000000000..47ed85a18c --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js @@ -0,0 +1,16 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/*--- +es5id: 12.2.2_b +description: > + Tests that Intl.DateTimeFormat.supportedLocalesOf doesn't access + arguments that it's not given. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +taintDataProperty(Object.prototype, "1"); +new Intl.DateTimeFormat("und"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js new file mode 100644 index 0000000000..a05e77b80e --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_22 +description: > + Tests that the behavior of a Record is not affected by + adversarial changes to Object.prototype. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZone"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + "."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js new file mode 100644 index 0000000000..6b51db065d --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js @@ -0,0 +1,18 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that the behavior of a Record is not affected by + adversarial changes to Object.prototype. +includes: [testIntl.js] +features: [Intl.DateTimeFormat-dayPeriod] +---*/ + +taintProperties(["dayPeriod"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + "."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js new file mode 100644 index 0000000000..8792628e97 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js @@ -0,0 +1,18 @@ +// Copyright 2019 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-createdatetimeformat +description: > + Tests that the behavior of a Record is not affected by + adversarial changes to Object.prototype. +includes: [testIntl.js] +features: [Intl.DateTimeFormat-fractionalSecondDigits] +---*/ + +taintProperties(["fractionalSecondDigits"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + "."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js new file mode 100644 index 0000000000..5dd7b61535 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_5 +description: > + Tests that the behavior of a Record is not affected by + adversarial changes to Object.prototype. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +taintProperties(["localeMatcher"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + "."); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js new file mode 100644 index 0000000000..a0e0a16dc7 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js @@ -0,0 +1,17 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_23 +description: > + Tests that the options for the date and time components are + processed correctly. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +getDateTimeComponents().forEach(function (component) { + testOption(Intl.DateTimeFormat, component, "string", getDateTimeComponentValues(component), undefined, {isILD: true}); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js new file mode 100644 index 0000000000..41c25d6e99 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_25 +description: Tests that the option formatMatcher is processed correctly. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +testOption(Intl.DateTimeFormat, "formatMatcher", "string", ["basic", "best fit"], "best fit", {noReturn: true}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js new file mode 100644 index 0000000000..c6a4124bf9 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js @@ -0,0 +1,16 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_18 +description: Tests that the option hour12 is processed correctly. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined, + {extra: {any: {hour: "numeric", minute: "numeric"}}}); +testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined, + {noReturn: true}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js new file mode 100644 index 0000000000..6adf184682 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 12.1.1_6 +description: Tests that the option localeMatcher is processed correctly. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +testOption(Intl.DateTimeFormat, "localeMatcher", "string", ["lookup", "best fit"], "best fit", {noReturn: true}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js b/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js new file mode 100644 index 0000000000..e96110d1ca --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js @@ -0,0 +1,37 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-intl-datetimeformat-constructor +description: > + Tests that the this-value is ignored in DateTimeFormat, if the this-value + isn't a DateTimeFormat instance. +author: Norbert Lindenberg +includes: [testIntl.js] +---*/ + +testWithIntlConstructors(function (Constructor) { + if (Constructor === Intl.DateTimeFormat) + return; + + var obj, newObj; + + // variant 1: use constructor in a "new" expression + obj = new Constructor(); + newObj = Intl.DateTimeFormat.call(obj); + assert.notSameValue(obj, newObj, "DateTimeFormat object created with \"new\" was not ignored as this-value."); + + // variant 2: use constructor as a function + if (Constructor !== Intl.Collator && + Constructor !== Intl.NumberFormat && + Constructor !== Intl.DateTimeFormat) + { + // Newer Intl constructors are not callable as a function. + return; + } + obj = Constructor(); + newObj = Intl.DateTimeFormat.call(obj); + assert.notSameValue(obj, newObj, "DateTimeFormat object created with constructor as function was not ignored as this-value."); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js new file mode 100644 index 0000000000..f52468843a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js @@ -0,0 +1,638 @@ +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-initializedatetimeformat +description: Time zone identifiers are case-normalized +---*/ + +const timeZoneIdentifiers = [ + // IANA TZDB Zone names + "Africa/Abidjan", + "Africa/Algiers", + "Africa/Bissau", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/El_Aaiun", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Khartoum", + "Africa/Lagos", + "Africa/Maputo", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Sao_Tome", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Asuncion", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Cayenne", + "America/Chicago", + "America/Chihuahua", + // 'America/Ciudad_Juarez' // uncomment after Node supports this ID added in TZDB 2022g + "America/Costa_Rica", + "America/Cuiaba", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Fort_Nelson", + "America/Fortaleza", + "America/Glace_Bay", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/New_York", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Sitka", + "America/St_Johns", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Tijuana", + "America/Toronto", + "America/Vancouver", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/Troll", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Colombo", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kathmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuching", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Riyadh", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ulaanbaatar", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faroe", + "Atlantic/Madeira", + "Atlantic/South_Georgia", + "Atlantic/Stanley", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/Perth", + "Australia/Sydney", + "CET", + "CST6CDT", + "EET", + "EST", + "EST5EDT", + "Etc/GMT", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/UTC", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Chisinau", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Helsinki", + "Europe/Istanbul", + "Europe/Kaliningrad", + "Europe/Kirov", + "Europe/Kyiv", + "Europe/Lisbon", + "Europe/London", + "Europe/Madrid", + "Europe/Malta", + "Europe/Minsk", + "Europe/Moscow", + "Europe/Paris", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Sofia", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Ulyanovsk", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zurich", + "HST", + "Indian/Chagos", + "Indian/Maldives", + "Indian/Mauritius", + "MET", + "MST", + "MST7MDT", + "PST8PDT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Kanton", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Marquesas", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + + // IANA TZDB Link names + "WET", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Kampala", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Timbuktu", + "America/Anguilla", + "America/Antigua", + "America/Argentina/ComodRivadavia", + "America/Aruba", + "America/Atikokan", + "America/Atka", + "America/Blanc-Sablon", + "America/Buenos_Aires", + "America/Catamarca", + "America/Cayman", + "America/Coral_Harbour", + "America/Cordoba", + "America/Creston", + "America/Curacao", + "America/Dominica", + "America/Ensenada", + "America/Fort_Wayne", + "America/Godthab", + "America/Grenada", + "America/Guadeloupe", + "America/Indianapolis", + "America/Jujuy", + "America/Knox_IN", + "America/Kralendijk", + "America/Louisville", + "America/Lower_Princes", + "America/Marigot", + "America/Mendoza", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/Nipigon", + "America/Pangnirtung", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Rainy_River", + "America/Rosario", + "America/Santa_Isabel", + "America/Shiprock", + "America/St_Barthelemy", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Thunder_Bay", + "America/Tortola", + "America/Virgin", + "Antarctica/DumontDUrville", + "Antarctica/McMurdo", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Ashkhabad", + "Asia/Bahrain", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Dacca", + "Asia/Harbin", + "Asia/Istanbul", + "Asia/Kashgar", + "Asia/Katmandu", + "Asia/Kuala_Lumpur", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Muscat", + "Asia/Phnom_Penh", + "Asia/Rangoon", + "Asia/Saigon", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Ujung_Pandang", + "Asia/Ulan_Bator", + "Asia/Vientiane", + "Atlantic/Faeroe", + "Atlantic/Jan_Mayen", + "Atlantic/Reykjavik", + "Atlantic/St_Helena", + "Australia/ACT", + "Australia/Canberra", + "Australia/Currie", + "Australia/LHI", + "Australia/NSW", + "Australia/North", + "Australia/Queensland", + "Australia/South", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "Egypt", + "Eire", + "Etc/GMT+0", + "Etc/GMT-0", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/Universal", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Belfast", + "Europe/Bratislava", + "Europe/Busingen", + "Europe/Copenhagen", + "Europe/Guernsey", + "Europe/Isle_of_Man", + "Europe/Jersey", + "Europe/Kiev", + "Europe/Ljubljana", + "Europe/Luxembourg", + "Europe/Mariehamn", + "Europe/Monaco", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Podgorica", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Skopje", + "Europe/Stockholm", + "Europe/Tiraspol", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Zagreb", + "Europe/Zaporozhye", + "GB", + "GB-Eire", + "GMT", + "GMT+0", + "GMT-0", + "GMT0", + "Greenwich", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "NZ", + "NZ-CHAT", + "Navajo", + "PRC", + "Pacific/Chuuk", + "Pacific/Enderbury", + "Pacific/Funafuti", + "Pacific/Johnston", + "Pacific/Majuro", + "Pacific/Midway", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "ROC", + "ROK", + "Singapore", + "Turkey", + "UCT", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Pacific-New", + "US/Samoa", + "UTC", + "Universal", + "W-SU", + "Zulu" +]; + +// We want to test all available named time zone identifiers (both primary and non-primary), +// but no ECMAScript built-in API exposes that list. So we use a union of two sources: +// 1. A hard-coded list of Zone and Link identifiers from the 2022g version of IANA TZDB. +// 2. Canonical IDs exposed by Intl.supportedValuesOf('timeZone'), which ensures that IDs +// added to TZDB later than 2022g will be tested. (New IDs are almost always added as primary.) +const ids = [...new Set([...timeZoneIdentifiers, ...Intl.supportedValuesOf("timeZone")])]; +for (const id of ids) { + const lower = id.toLowerCase(); + const upper = id.toUpperCase(); + assert.sameValue( + new Intl.DateTimeFormat("en", { timeZone: id }).resolvedOptions().timeZone, + id, + `Time zone created from string "${id}"` + ); + assert.sameValue( + new Intl.DateTimeFormat("en", { timeZone: upper }).resolvedOptions().timeZone, + id, + `Time zone created from string "${upper}"` + ); + assert.sameValue( + new Intl.DateTimeFormat("en", { timeZone: lower }).resolvedOptions().timeZone, + id, + `Time zone created from string "${lower}"` + ); +} + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js new file mode 100644 index 0000000000..f42ffd0201 --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js @@ -0,0 +1,28 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 6.4_b +description: Tests that invalid time zone names are not accepted. +author: Norbert Lindenberg +---*/ + +var invalidTimeZoneNames = [ + "", + "MEZ", // localized abbreviation + "Pacific Time", // localized long form + "cnsha", // BCP 47 time zone code + "invalid", // as the name says + "Europe/İstanbul", // non-ASCII letter + "asıa/baku", // non-ASCII letter + "europe/brußels" // non-ASCII letter +]; + +invalidTimeZoneNames.forEach(function (name) { + // this must throw an exception for an invalid time zone name + assert.throws(RangeError, function() { + var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name}); + }, "Invalid time zone name " + name + " was not rejected."); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js new file mode 100644 index 0000000000..7218ad448b --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Justin Grant. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-initializedatetimeformat +description: Time zone identifiers are not canonicalized before storing in internal slots +---*/ + +const baseOptions = { + timeZoneName: "long", + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric" +}; +const dtf1 = new Intl.DateTimeFormat("en", { ...baseOptions, timeZone: "Asia/Calcutta" }); +const dtf2 = new Intl.DateTimeFormat("en", { ...baseOptions, timeZone: "Asia/Kolkata" }); + +const resolvedId1 = dtf1.resolvedOptions().timeZone; +const resolvedId2 = dtf2.resolvedOptions().timeZone; + +const output1 = dtf1.format(0); +const output2 = dtf2.format(0); + +assert.sameValue(output1, output2); +assert.sameValue(resolvedId1, "Asia/Calcutta"); +assert.sameValue(resolvedId2, "Asia/Kolkata"); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js new file mode 100644 index 0000000000..f27d109b1a --- /dev/null +++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es5id: 6.4_a +description: Tests that valid time zone names are accepted. +author: Norbert Lindenberg +---*/ + +var validTimeZoneNames = [ + "UTC", + "utc" // time zone names are case-insensitive +]; + +validTimeZoneNames.forEach(function (name) { + // this must not throw an exception for a valid time zone name + var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name}); + assert.sameValue(format.resolvedOptions().timeZone, name.toUpperCase(), "Time zone name " + name + " was not correctly accepted."); +}); + +reportCompare(0, 0); -- cgit v1.2.3