summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/intl402/Intl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/intl402/Intl
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/intl402/Intl')
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/fails-on-distinct-temporal-types.js36
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/fails-on-distinct-temporal-types.js36
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/DateTimeFormat/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/builtin.js21
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/Locale-object.js30
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-tags.js66
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-unicode-ext-seq.js41
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-language-subtag-replacement.js60
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-region-subtag-replacement.js110
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/descriptor.js24
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/duplicates.js20
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/elements-not-reordered.js29
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/error-cases.js48
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/get-locale.js27
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/getCanonicalLocales.js26
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/grandfathered.js35
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/has-property.js32
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/invalid-tags.js32
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/length.js21
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/locales-is-not-a-string.js33
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/main.js34
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/name.js21
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/non-iana-canon.js81
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-arg-length.js103
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-push.js21
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-grandfathered.js98
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-variant.js60
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-an-array.js24
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-mutable.js49
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/to-string.js22
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js56
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-invalid.js80
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-valid.js80
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-calendar.js60
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-col-strength.js67
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-measurement-system.js51
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-region.js69
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-subdivision.js74
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-timezone.js74
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-yes-to-true.js88
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js56
-rw-r--r--js/src/tests/test262/intl402/Intl/getCanonicalLocales/weird-cases.js26
-rw-r--r--js/src/tests/test262/intl402/Intl/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/builtin.js44
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DateTimeFormat.js47
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DisplayNames.js47
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars.js56
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/coerced-to-string.js38
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/collations-accepted-by-Collator.js83
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/collations.js58
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-DisplayNames.js53
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-NumberFormat.js46
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies.js50
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/invalid-key.js45
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/length.js32
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/name.js34
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-DateTimeFormat.js50
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-NumberFormat.js50
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-RelativeTimeFormat.js50
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-with-simple-digit-mappings.js38
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems.js57
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/prop-desc.js25
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/shell.js24
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones-accepted-by-DateTimeFormat.js46
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones.js59
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/units-accepted-by-NumberFormat.js47
-rw-r--r--js/src/tests/test262/intl402/Intl/supportedValuesOf/units.js50
-rw-r--r--js/src/tests/test262/intl402/Intl/toStringTag/browser.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/toStringTag/shell.js0
-rw-r--r--js/src/tests/test262/intl402/Intl/toStringTag/toString.js34
-rw-r--r--js/src/tests/test262/intl402/Intl/toStringTag/toStringTag.js25
82 files changed, 3209 insertions, 0 deletions
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/browser.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/browser.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/browser.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/fails-on-distinct-temporal-types.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/fails-on-distinct-temporal-types.js
new file mode 100644
index 0000000000..9bac489052
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/fails-on-distinct-temporal-types.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 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: formatRange fails if given arguments of different Temporal types
+features: [Temporal]
+---*/
+
+const us = new Intl.DateTimeFormat('en-US');
+
+const instances = {
+ date: new Date(1580527800000),
+ instant: new Temporal.Instant(0n),
+ plaindate: new Temporal.PlainDate(2000, 5, 2),
+ plaindatetime: new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321),
+ plainmonthday: new Temporal.PlainMonthDay(5, 2),
+ plaintime: new Temporal.PlainTime(13, 37),
+ plainyearmonth: new Temporal.PlainYearMonth(2019, 6),
+ zoneddatetime: new Temporal.ZonedDateTime(0n, 'America/Kentucky/Louisville')
+};
+
+Object.entries(instances).forEach(([typeName, instance]) => {
+ Object.entries(instances).forEach(([anotherTypeName, anotherInstance]) => {
+ if (typeName !== anotherTypeName) {
+ assert.throws(
+ TypeError,
+ () => { us.formatRange(instance, anotherInstance); },
+ 'formatRange: bad arguments (' + typeName + ' and ' + anotherTypeName + ')'
+ );
+ }
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/shell.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRange/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/browser.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/fails-on-distinct-temporal-types.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/fails-on-distinct-temporal-types.js
new file mode 100644
index 0000000000..8fcc1a54e2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/fails-on-distinct-temporal-types.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 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: formatRange fails if given arguments of different Temporal types
+features: [Temporal]
+---*/
+
+const us = new Intl.DateTimeFormat('en-US');
+
+const instances = {
+ date: new Date(1580527800000),
+ instant: new Temporal.Instant(0n),
+ plaindate: new Temporal.PlainDate(2000, 5, 2),
+ plaindatetime: new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321),
+ plainmonthday: new Temporal.PlainMonthDay(5, 2),
+ plaintime: new Temporal.PlainTime(13, 37),
+ plainyearmonth: new Temporal.PlainYearMonth(2019, 6),
+ zoneddatetime: new Temporal.ZonedDateTime(0n, 'America/Kentucky/Louisville')
+};
+
+Object.entries(instances).forEach(([typeName, instance]) => {
+ Object.entries(instances).forEach(([anotherTypeName, anotherInstance]) => {
+ if (typeName !== anotherTypeName) {
+ assert.throws(
+ TypeError,
+ () => { us.formatRangeToParts(instance, anotherInstance); },
+ 'formatRange: bad arguments (' + typeName + ' and ' + anotherTypeName + ')'
+ );
+ }
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/shell.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/formatRangeToParts/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/shell.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/prototype/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/DateTimeFormat/shell.js b/js/src/tests/test262/intl402/Intl/DateTimeFormat/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/DateTimeFormat/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/browser.js b/js/src/tests/test262/intl402/Intl/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/builtin.js b/js/src/tests/test262/intl402/Intl/builtin.js
new file mode 100644
index 0000000000..7641f06945
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/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.
+
+/*---
+esid: intl-object
+description: >
+ Tests that Intl 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), "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(Intl), Object.prototype,
+ "The [[Prototype]] of Intl is %ObjectPrototype%.");
+
+assert.sameValue(this.Intl, Intl,
+ "%Intl% is accessible as a property of the global object.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/Locale-object.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/Locale-object.js
new file mode 100644
index 0000000000..49ed15f8cc
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/Locale-object.js
@@ -0,0 +1,30 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests for Locale objects in the argument to getCanonicalLocales
+info: |
+ CanonicalizeLocaleList ( locales )
+ 7. c. iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then
+ 1. Let tag be kValue.[[Locale]].
+includes: [compareArray.js]
+features: [Intl.Locale]
+---*/
+
+assert.compareArray(Intl.getCanonicalLocales([
+ "fr-CA",
+ new Intl.Locale("en-gb-oxendict"),
+ "de",
+ new Intl.Locale("jp", { "calendar": "gregory" }),
+ "zh",
+ new Intl.Locale("fr-CA"),
+]), [
+ "fr-CA",
+ "en-GB-oxendict",
+ "de",
+ "jp-u-ca-gregory",
+ "zh",
+]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/browser.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-tags.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-tags.js
new file mode 100644
index 0000000000..f80e448086
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-tags.js
@@ -0,0 +1,66 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Call Intl.getCanonicalLocales function with valid language tags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ a. Let Pk be ToString(k).
+ b. Let kPresent be ? HasProperty(O, Pk).
+ c. If kPresent is true, then
+ i. Let kValue be ? Get(O, Pk).
+ ...
+ iii. Let tag be ? ToString(kValue).
+ ...
+ v. Let canonicalizedTag be CanonicalizeLanguageTag(tag).
+ vi. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen.
+ ...
+includes: [testIntl.js]
+---*/
+
+var canonicalizedTags = {
+ "de": "de",
+ "DE-de": "de-DE",
+ "de-DE": "de-DE",
+ "cmn": "zh",
+ "CMN-hANS": "zh-Hans",
+ "cmn-hans-cn": "zh-Hans-CN",
+ "es-419": "es-419",
+ "es-419-u-nu-latn": "es-419-u-nu-latn",
+ "cmn-hans-cn-u-ca-t-ca-x-t-u": "zh-Hans-CN-t-ca-u-ca-x-t-u",
+ "de-gregory-u-ca-gregory": "de-gregory-u-ca-gregory",
+ "sgn-GR": "gss",
+ "ji": "yi",
+ "de-DD": "de-DE",
+ "in": "id",
+ "sr-cyrl-ekavsk": "sr-Cyrl-ekavsk",
+ "en-ca-newfound": "en-CA-newfound",
+ "sl-rozaj-biske-1994": "sl-1994-biske-rozaj",
+ "da-u-attr": "da-u-attr",
+ "da-u-attr-co-search": "da-u-attr-co-search",
+};
+
+// make sure the data above is correct
+Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
+ var canonicalizedTag = canonicalizedTags[tag];
+ assert(
+ isCanonicalizedStructurallyValidLanguageTag(canonicalizedTag),
+ "Test data \"" + canonicalizedTag + "\" is not canonicalized and structurally valid language tag."
+ );
+});
+
+Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
+ var canonicalLocales = Intl.getCanonicalLocales(tag);
+ assert.sameValue(canonicalLocales.length, 1);
+ assert.sameValue(canonicalLocales[0], canonicalizedTags[tag]);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-unicode-ext-seq.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-unicode-ext-seq.js
new file mode 100644
index 0000000000..07edfac0e7
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/canonicalized-unicode-ext-seq.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Implementations are allowed to canonicalize extension subtag sequences.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. Let canonicalizedTag be CanonicalizeLanguageTag(tag).
+ ...
+
+ 6.2.3 CanonicalizeLanguageTag (locale)
+ The specifications for extensions to BCP 47 language tags, such as
+ RFC 6067, may include canonicalization rules for the extension subtag
+ sequences they define that go beyond the canonicalization rules of
+ RFC 5646 section 4.5. Implementations are allowed, but not required,
+ to apply these additional rules.
+---*/
+
+var locale = "it-u-nu-latn-ca-gregory";
+
+// RFC 6067: The canonical order of keywords is in US-ASCII order by key.
+var sorted = "it-u-ca-gregory-nu-latn";
+
+var canonicalLocales = Intl.getCanonicalLocales(locale);
+assert.sameValue(canonicalLocales.length, 1);
+
+var canonicalLocale = canonicalLocales[0];
+assert((canonicalLocale === locale) || (canonicalLocale === sorted));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-language-subtag-replacement.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-language-subtag-replacement.js
new file mode 100644
index 0000000000..1401971928
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-language-subtag-replacement.js
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Assert non-simple language subtag replacements work as expected.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+
+ - Replace aliases in the unicode_language_id and tlang (if any) using the following process:
+ - If the language subtag matches the type attribute of a languageAlias element in
+ Supplemental Data, replace the language subtag with the replacement value.
+ 1. If there are additional subtags in the replacement value, add them to the result,
+ but only if there is no corresponding subtag already in the tag.
+
+includes: [testIntl.js]
+---*/
+
+// CLDR contains language mappings where in addition to the language subtag also
+// the script or region subtag is modified, unless they're already present.
+
+const testData = {
+ // "sh" adds "Latn", unless a script subtag is already present.
+ // <languageAlias type="sh" replacement="sr_Latn" reason="legacy"/>
+ "sh": "sr-Latn",
+ "sh-Cyrl": "sr-Cyrl",
+
+ // "cnr" adds "ME", unless a region subtag is already present.
+ // <languageAlias type="cnr" replacement="sr_ME" reason="legacy"/>
+ "cnr": "sr-ME",
+ "cnr-BA": "sr-BA",
+};
+
+for (let [tag, canonical] of Object.entries(testData)) {
+ // Make sure the test data is correct.
+ assert(
+ isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonicalized and structurally valid language tag."
+ );
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-region-subtag-replacement.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-region-subtag-replacement.js
new file mode 100644
index 0000000000..f8a316d6f2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/complex-region-subtag-replacement.js
@@ -0,0 +1,110 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Assert non-simple region subtag replacements work as expected.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+
+ - Replace aliases in the unicode_language_id and tlang (if any) using the following process:
+ - If the region subtag matches the type attribute of a territoryAlias element in
+ Supplemental Data, replace the language subtag with the replacement value, as follows:
+ 1. If there is a single territory in the replacement, use it.
+ 2. If there are multiple territories:
+ 1. Look up the most likely territory for the base language code (and script, if there is one).
+ 2. If that likely territory is in the list, use it.
+ 3. Otherwise, use the first territory in the list.
+
+includes: [testIntl.js]
+---*/
+
+// CLDR contains region mappings where the replacement region depends on the
+// likely subtags from the language and script subtags.
+
+const testData = {
+ // For example, the breakup of the Soviet Union ("SU") means that the region of
+ // the Soviet Union ("SU") is replaced by Russia ("RU"), Armenia ("AM"), or
+ // many others -- depending on the specified (or merely likely) language and
+ // script subtags:
+ //
+ // <territoryAlias type="SU" replacement="RU AM AZ BY EE GE KZ KG LV LT MD TJ TM UA UZ" reason="deprecated"/>
+ // <territoryAlias type="810" replacement="RU AM AZ BY EE GE KZ KG LV LT MD TJ TM UA UZ" reason="overlong"/>
+ "ru-SU": "ru-RU",
+ "ru-810": "ru-RU",
+ "en-SU": "en-RU",
+ "en-810": "en-RU",
+ "und-SU": "und-RU",
+ "und-810": "und-RU",
+ "und-Latn-SU": "und-Latn-RU",
+ "und-Latn-810": "und-Latn-RU",
+
+ // Armenia can be the preferred region when the language is "hy" (Armenian) or
+ // the script is "Armn" (Armenian).
+ //
+ // <likelySubtag from="hy" to="hy_Armn_AM"/>
+ // <likelySubtag from="und_Armn" to="hy_Armn_AM"/>
+ "hy-SU": "hy-AM",
+ "hy-810": "hy-AM",
+ "und-Armn-SU": "und-Armn-AM",
+ "und-Armn-810": "und-Armn-AM",
+
+ // <territoryAlias type="CS" replacement="RS ME" reason="deprecated"/>
+ //
+ // The following likely-subtags entries contain "RS" and "ME":
+ //
+ // <likelySubtag from="sr" to="sr_Cyrl_RS"/>
+ // <likelySubtag from="sr_ME" to="sr_Latn_ME"/>
+ // <likelySubtag from="und_RS" to="sr_Cyrl_RS"/>
+ // <likelySubtag from="und_ME" to="sr_Latn_ME"/>
+ //
+ // In this case there is no language/script combination (without a region
+ // subtag) where "ME" is ever chosen, so the replacement is always "RS".
+ "sr-CS": "sr-RS",
+ "sr-Latn-CS": "sr-Latn-RS",
+ "sr-Cyrl-CS": "sr-Cyrl-RS",
+
+ // The existing region in the source locale identifier is ignored when selecting
+ // the likely replacement region. For example take "az-NT", which is Azerbaijani
+ // spoken in the Neutral Zone. The replacement region for "NT" is either
+ // "SA" (Saudi-Arabia) or "IQ" (Iraq), and there is also a likely subtags entry
+ // for "az-IQ". But when only looking at the language subtag in "az-NT", "az" is
+ // always resolved to "az-Latn-AZ", and because "AZ" is not in the list ["SA",
+ // "IQ"], the final replacement region is the default for "NT", namely "SA".
+ // That means "az-NT" will be canonicalised to "az-SA" and not "az-IQ", even
+ // though the latter may be a more sensible candidate based on the actual usage
+ // of the target locales.
+ //
+ // <territoryAlias type="NT" replacement="SA IQ" reason="deprecated"/>
+ // <likelySubtag from="az_IQ" to="az_Arab_IQ"/>
+ // <likelySubtag from="az" to="az_Latn_AZ"/>
+ "az-NT": "az-SA",
+};
+
+for (let [tag, canonical] of Object.entries(testData)) {
+ // Make sure the test data is correct.
+ assert(
+ isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonicalized and structurally valid language tag."
+ );
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/descriptor.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/descriptor.js
new file mode 100644
index 0000000000..4251540049
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/descriptor.js
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Intl.getCanonicalLocales property attributes.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+
+ 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, 'getCanonicalLocales', {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/duplicates.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/duplicates.js
new file mode 100644
index 0000000000..a3697544c0
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/duplicates.js
@@ -0,0 +1,20 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests the getCanonicalLocales function for duplicate locales scenario.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [compareArray.js]
+---*/
+
+assert.compareArray(Intl.getCanonicalLocales(
+ ['ab-cd', 'ff', 'de-rt', 'ab-Cd']), ['ab-CD', 'ff', 'de-RT']);
+
+var locales = Intl.getCanonicalLocales(['en-US', 'en-US']);
+assert.compareArray(locales, ['en-US'], 'en-US');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/elements-not-reordered.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/elements-not-reordered.js
new file mode 100644
index 0000000000..67a1239d62
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/elements-not-reordered.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Language tags are not reordered.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ vi. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen.
+ ...
+---*/
+
+var canonicalLocales = Intl.getCanonicalLocales(["zu", "af"]);
+
+assert.sameValue(canonicalLocales.length, 2);
+assert.sameValue(canonicalLocales[0], "zu");
+assert.sameValue(canonicalLocales[1], "af");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/error-cases.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/error-cases.js
new file mode 100644
index 0000000000..b0c4b8a9a8
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/error-cases.js
@@ -0,0 +1,48 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests the getCanonicalLocales function for error tags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+features: [Symbol]
+---*/
+
+var rangeErrorCases =
+ [
+ "en-us-",
+ "-en-us",
+ "en-us-en-us",
+ "--",
+ "-",
+ "",
+ "-e-"
+ ];
+
+rangeErrorCases.forEach(function(re) {
+ assert.throws(RangeError, function() {
+ Intl.getCanonicalLocales(re);
+ });
+});
+
+var typeErrorCases =
+ [
+ null,
+ [null],
+ [undefined],
+ [true],
+ [NaN],
+ [2],
+ [Symbol('foo')]
+ ];
+
+typeErrorCases.forEach(function(te) {
+ assert.throws(TypeError, function() {
+ Intl.getCanonicalLocales(te);
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/get-locale.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/get-locale.js
new file mode 100644
index 0000000000..99032e02c9
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/get-locale.js
@@ -0,0 +1,27 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Test Intl.getCanonicalLocales for step 7.c.i.
+info: |
+ 9.2.1 CanonicalizeLocaleList (locales)
+ 7. Repeat, while k < len.
+ c. If kPresent is true, then
+ i. Let kValue be ? Get(O, Pk).
+---*/
+
+var locales = {
+ '0': 'en-US',
+ length: 2
+};
+
+Object.defineProperty(locales, "1", {
+ get: function() { throw new Test262Error() }
+});
+
+assert.throws(Test262Error, function() {
+ Intl.getCanonicalLocales(locales);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/getCanonicalLocales.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/getCanonicalLocales.js
new file mode 100644
index 0000000000..77dc3f786b
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/getCanonicalLocales.js
@@ -0,0 +1,26 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Property type and descriptor.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [propertyHelper.js]
+---*/
+
+assert.sameValue(
+ typeof Intl.getCanonicalLocales,
+ 'function',
+ '`typeof Intl.getCanonicalLocales` is `function`'
+);
+
+verifyProperty(Intl, "getCanonicalLocales", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/grandfathered.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/grandfathered.js
new file mode 100644
index 0000000000..4a26d4d2e0
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/grandfathered.js
@@ -0,0 +1,35 @@
+// Copyright 2018 André Bargull; Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+// Split from intl402/Locale/likely-subtags-grandfathered.js
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Verifies canonicalization of specific tags.
+---*/
+
+
+const regularGrandfathered = [
+ {
+ tag: "art-lojban",
+ canonical: "jbo",
+ },
+ {
+ tag: "zh-guoyu",
+ canonical: "zh",
+ },
+ {
+ tag: "zh-hakka",
+ canonical: "hak",
+ },
+ {
+ tag: "zh-xiang",
+ canonical: "hsn",
+ },
+];
+
+for (const {tag, canonical} of regularGrandfathered) {
+ assert.sameValue(Intl.getCanonicalLocales(tag)[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/has-property.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/has-property.js
new file mode 100644
index 0000000000..2c77014cec
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/has-property.js
@@ -0,0 +1,32 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Test Intl.getCanonicalLocales.name for step 7.b.
+info: |
+ 9.2.1 CanonicalizeLocaleList (locales)
+ 7. Repeat, while k < len.
+ b. Let kPresent be HasProperty(O, Pk).
+features: [Proxy]
+---*/
+
+var locales = {
+ '0': 'en-US',
+ '1': 'pt-BR',
+ length: 2
+};
+
+var p = new Proxy(locales, {
+ has: function(_, prop) {
+ if (prop === '0') {
+ throw new Test262Error();
+ }
+ }
+});
+
+assert.throws(Test262Error, function() {
+ Intl.getCanonicalLocales(p);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/invalid-tags.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/invalid-tags.js
new file mode 100644
index 0000000000..22949e8370
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/invalid-tags.js
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Throws a RangeError if the language tag is invalid.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ ...
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ iv. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ ...
+includes: [testIntl.js]
+---*/
+
+var invalidLanguageTags = getInvalidLanguageTags();
+for (var i = 0; i < invalidLanguageTags.length; ++i) {
+ var invalidTag = invalidLanguageTags[i];
+ assert.throws(RangeError, function() {
+ Intl.getCanonicalLocales(invalidTag)
+ }, "Language tag: " + invalidTag);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/length.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/length.js
new file mode 100644
index 0000000000..d4bdecd5e0
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/length.js
@@ -0,0 +1,21 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Intl.getCanonicalLocales.length.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.getCanonicalLocales, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/locales-is-not-a-string.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/locales-is-not-a-string.js
new file mode 100644
index 0000000000..2aa0565785
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/locales-is-not-a-string.js
@@ -0,0 +1,33 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests for scenario where locales is not a string
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [compareArray.js]
+features: [Symbol]
+---*/
+
+var gCL = Intl.getCanonicalLocales;
+
+function assertArray(l, r) {
+ assert.compareArray(l, r, r);
+}
+
+assertArray(gCL(), []);
+assertArray(gCL(undefined), []);
+assertArray(gCL(false), []);
+assertArray(gCL(true), []);
+assertArray(gCL(Symbol("foo")), []);
+assertArray(gCL(NaN), []);
+assertArray(gCL(1), []);
+
+Number.prototype[0] = "en-US";
+Number.prototype.length = 1;
+assertArray(gCL(NaN), ["en-US"]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/main.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/main.js
new file mode 100644
index 0000000000..6881431838
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/main.js
@@ -0,0 +1,34 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests for existance and behavior of Intl.getCanonicalLocales
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [compareArray.js]
+---*/
+
+var gCL = Intl.getCanonicalLocales;
+
+function assertArray(l, r) {
+ assert.compareArray(l, r, r);
+}
+
+assertArray(gCL(), []);
+
+assertArray(gCL('ab-cd'), ['ab-CD']);
+
+assertArray(gCL(['ab-cd']), ['ab-CD']);
+
+assertArray(gCL(['ab-cd', 'FF']), ['ab-CD', 'ff']);
+
+assertArray(gCL({'a': 0}), []);
+
+assertArray(gCL({}), []);
+
+assertArray(gCL(['th-th-u-nu-thai']), ['th-TH-u-nu-thai']);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/name.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/name.js
new file mode 100644
index 0000000000..c5984baec6
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/name.js
@@ -0,0 +1,21 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Intl.getCanonicalLocales.name value and descriptor.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.getCanonicalLocales, "name", {
+ value: "getCanonicalLocales",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/non-iana-canon.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/non-iana-canon.js
new file mode 100644
index 0000000000..5afd34591a
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/non-iana-canon.js
@@ -0,0 +1,81 @@
+// Copyright 2018 André Bargull; Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+// Slip from intl402/Locale/constructor-non-iana-canon.js
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Verifies canonicalization, of specific tags.
+info: |
+ ApplyOptionsToTag( tag, options )
+ 10. Return CanonicalizeLanguageTag(tag).
+---*/
+
+// Test some language tags where we know that either CLDR or ICU produce
+// different results compared to the canonicalization specified in RFC 5646.
+var testData = [
+ {
+ tag: "mo",
+ canonical: "ro",
+ },
+ {
+ tag: "es-ES-preeuro",
+ },
+ {
+ tag: "uz-UZ-cyrillic",
+ },
+ {
+ tag: "posix",
+ },
+ {
+ tag: "hi-direct",
+ },
+ {
+ tag: "zh-pinyin",
+ },
+ {
+ tag: "zh-stroke",
+ },
+ {
+ tag: "aar-x-private",
+ // "aar" should be canonicalized into "aa" because "aar" matches the type attribute of
+ // a languageAlias element in
+ // https://www.unicode.org/repos/cldr/trunk/common/supplemental/supplementalMetadata.xml
+ canonical: "aa-x-private",
+ },
+ {
+ tag: "heb-x-private",
+ // "heb" should be canonicalized into "he" because "heb" matches the type attribute of
+ // a languageAlias element in
+ // https://www.unicode.org/repos/cldr/trunk/common/supplemental/supplementalMetadata.xml
+ canonical: "he-x-private",
+ },
+ {
+ tag: "de-u-kf",
+ },
+ {
+ tag: "ces",
+ // "ces" should be canonicalized into "cs" because "ces" matches the type attribute of
+ // a languageAlias element in
+ // https://www.unicode.org/repos/cldr/trunk/common/supplemental/supplementalMetadata.xml
+ canonical: "cs",
+ },
+ {
+ tag: "hy-arevela",
+ canonical: "hy",
+ },
+ {
+ tag: "hy-arevmda",
+ canonical: "hyw",
+ },
+];
+
+for (const {tag, canonical = tag} of testData) {
+ assert.sameValue(
+ Intl.getCanonicalLocales(tag)[0],
+ canonical,
+ 'The value of Intl.getCanonicalLocales(tag)[0] equals the value of `canonical`'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-arg-length.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-arg-length.js
new file mode 100644
index 0000000000..3d781c0301
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-arg-length.js
@@ -0,0 +1,103 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Test Intl.getCanonicalLocales for step 5.
+info: |
+ 9.2.1 CanonicalizeLocaleList (locales)
+ 5. Let len be ? ToLength(? Get(O, "length")).
+includes: [compareArray.js]
+features: [Symbol]
+---*/
+
+var locales = {
+ '0': 'en-US',
+};
+
+Object.defineProperty(locales, "length", {
+ get: function() { throw new Test262Error() }
+});
+
+assert.throws(Test262Error, function() {
+ Intl.getCanonicalLocales(locales);
+}, "should throw if locales.length throws");
+
+var locales = {
+ '0': 'en-US',
+ '1': 'pt-BR',
+};
+
+Object.defineProperty(locales, "length", {
+ get: function() { return "1" }
+});
+
+assert.compareArray(
+ Intl.getCanonicalLocales(locales),
+ ['en-US'],
+ "should return one element if locales.length is '1'"
+);
+
+var locales = {
+ '0': 'en-US',
+ '1': 'pt-BR',
+};
+
+Object.defineProperty(locales, "length", {
+ get: function() { return 1.3 }
+});
+
+assert.compareArray(
+ Intl.getCanonicalLocales(locales),
+ ['en-US'],
+ "should return one element if locales.length is 1.3"
+);
+
+var locales = {
+ '0': 'en-US',
+ '1': 'pt-BR',
+};
+
+Object.defineProperty(locales, "length", {
+ get: function() { return Symbol("1.8") }
+});
+
+assert.throws(TypeError, function() {
+ Intl.getCanonicalLocales(locales);
+}, "should throw if locales.length is a Symbol");
+
+var locales = {
+ '0': 'en-US',
+ '1': 'pt-BR',
+};
+
+Object.defineProperty(locales, "length", {
+ get: function() { return -Infinity }
+});
+
+assert.compareArray(
+ Intl.getCanonicalLocales(locales),
+ [],
+ "should return empty array if locales.length is -Infinity"
+);
+
+var locales = {
+ length: -Math.pow(2, 32) + 1
+};
+
+Object.defineProperty(locales, "0", {
+ get: function() { throw new Error("must not be gotten!"); }
+})
+
+assert.compareArray(
+ Intl.getCanonicalLocales(locales),
+ [],
+ "should return empty array if locales.length is a negative value"
+);
+
+var count = 0;
+var locs = { get length() { if (count++ > 0) throw 42; return 0; } };
+var locales = Intl.getCanonicalLocales(locs); // shouldn't throw 42
+assert.sameValue(locales.length, 0);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-push.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-push.js
new file mode 100644
index 0000000000..d8c8a794ca
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/overriden-push.js
@@ -0,0 +1,21 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests the getCanonicalLocales function for overridden Array.push().
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [compareArray.js]
+---*/
+
+Array.prototype.push = function() { throw 42; };
+
+// must not throw 42, might if push is used
+var arr = Intl.getCanonicalLocales(["en-US"]);
+
+assert.compareArray(arr, ["en-US"]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-grandfathered.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-grandfathered.js
new file mode 100644
index 0000000000..51a536bbfc
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-grandfathered.js
@@ -0,0 +1,98 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Call Intl.getCanonicalLocales function with grandfathered language tags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. Let canonicalizedTag be CanonicalizeLanguageTag(tag).
+ ...
+
+ 6.2.3 CanonicalizeLanguageTag ( locale )
+ The CanonicalizeLanguageTag abstract operation returns the canonical and case-regularized form
+ of the locale argument (which must be a String value that is a structurally valid Unicode
+ BCP 47 Locale Identifier as verified by the IsStructurallyValidLanguageTag abstract operation).
+ A conforming implementation shall take the steps specified in the “BCP 47 Language Tag to
+ Unicode BCP 47 Locale Identifier” algorithm, from Unicode Technical Standard #35 LDML
+ § 3.3.1 BCP 47 Language Tag Conversion.
+
+includes: [testIntl.js]
+---*/
+
+// Generated from http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
+// File-Date: 2017-08-15
+
+var irregularGrandfathered = [
+ "en-gb-oed",
+ "i-ami",
+ "i-bnn",
+ "i-default",
+ "i-enochian",
+ "i-hak",
+ "i-klingon",
+ "i-lux",
+ "i-mingo",
+ "i-navajo",
+ "i-pwn",
+ "i-tao",
+ "i-tay",
+ "i-tsu",
+ "sgn-be-fr",
+ "sgn-be-nl",
+ "sgn-ch-de",
+];
+
+var regularGrandfatheredNonUTS35 = [
+ "no-bok",
+ "no-nyn",
+ "zh-min",
+ "zh-min-nan",
+];
+
+var regularGrandfatheredUTS35 = {
+ "art-lojban": "jbo",
+ "cel-gaulish": "xtg",
+ "zh-guoyu": "zh",
+ "zh-hakka": "hak",
+ "zh-xiang": "hsn",
+};
+
+// make sure the data above is correct
+irregularGrandfathered.forEach(function (tag) {
+ assert.sameValue(
+ isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "Test data \"" + tag + "\" is not a structurally valid language tag."
+ );
+});
+regularGrandfatheredNonUTS35.forEach(function (tag) {
+ assert.sameValue(
+ isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "Test data \"" + tag + "\" is not a structurally valid language tag."
+ );
+});
+Object.getOwnPropertyNames(regularGrandfatheredUTS35).forEach(function (tag) {
+ var canonicalizedTag = regularGrandfatheredUTS35[tag];
+ assert(
+ isCanonicalizedStructurallyValidLanguageTag(canonicalizedTag),
+ "Test data \"" + canonicalizedTag + "\" is a canonicalized and structurally valid language tag."
+ );
+});
+
+Object.getOwnPropertyNames(regularGrandfatheredUTS35).forEach(function (tag) {
+ var canonicalLocales = Intl.getCanonicalLocales(tag);
+ assert.sameValue(canonicalLocales.length, 1);
+ assert.sameValue(canonicalLocales[0], regularGrandfatheredUTS35[tag]);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-variant.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-variant.js
new file mode 100644
index 0000000000..e1d8f028cc
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/preferred-variant.js
@@ -0,0 +1,60 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Call Intl.getCanonicalLocales function with grandfathered language tags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. Let canonicalizedTag be CanonicalizeLanguageTag(tag).
+ ...
+
+ 6.2.3 CanonicalizeLanguageTag ( locale )
+ The CanonicalizeLanguageTag abstract operation returns the canonical and case-regularized
+ form of the locale argument (which must be a String value that is a structurally valid
+ BCP 47 language tag as verified by the IsStructurallyValidLanguageTag abstract operation).
+ A conforming implementation shall take the steps specified in RFC 5646 section 4.5, or
+ successor, to bring the language tag into canonical form, and to regularize the case of
+ the subtags. Furthermore, a conforming implementation shall not take the steps to bring
+ a language tag into "extlang form", nor shall it reorder variant subtags.
+
+ The specifications for extensions to BCP 47 language tags, such as RFC 6067, may include
+ canonicalization rules for the extension subtag sequences they define that go beyond the
+ canonicalization rules of RFC 5646 section 4.5. Implementations are allowed, but not
+ required, to apply these additional rules.
+
+includes: [testIntl.js]
+---*/
+
+// https://github.com/unicode-org/cldr/blame/master/common/supplemental/supplementalMetadata.xml#L531
+// http://unicode.org/reports/tr35/#LocaleId_Canonicalization
+var canonicalizedTags = {
+ "ja-latn-hepburn-heploc": "ja-Latn-alalc97",
+};
+
+// make sure the data above is correct
+Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
+ var canonicalizedTag = canonicalizedTags[tag];
+ assert(
+ isCanonicalizedStructurallyValidLanguageTag(canonicalizedTag),
+ "Test data \"" + canonicalizedTag + "\" is not canonicalized and structurally valid language tag."
+ );
+});
+
+Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
+ var canonicalLocales = Intl.getCanonicalLocales(tag);
+ assert.sameValue(canonicalLocales.length, 1);
+ assert.sameValue(canonicalLocales[0], canonicalizedTags[tag]);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-an-array.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-an-array.js
new file mode 100644
index 0000000000..193393484d
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-an-array.js
@@ -0,0 +1,24 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests that the value returned by getCanonicalLocales is an Array.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+---*/
+
+var locales = ['en-US'];
+var result = Intl.getCanonicalLocales(['en-US']);
+
+assert.sameValue(Object.getPrototypeOf(result), Array.prototype, 'prototype is Array.prototype');
+assert.sameValue(result.constructor, Array);
+
+assert.notSameValue(result, locales, "result is a new array instance");
+assert.sameValue(result.length, 1, "result.length");
+assert(result.hasOwnProperty("0"), "result an own property `0`");
+assert.sameValue(result[0], "en-US", "result[0]");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-mutable.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-mutable.js
new file mode 100644
index 0000000000..af9fd8c8c4
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/returned-object-is-mutable.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Tests that the value returned by getCanonicalLocales is a mutable array.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [propertyHelper.js]
+---*/
+
+var locales = ['en-US', 'fr'];
+var result = Intl.getCanonicalLocales(locales);
+
+verifyProperty(result, 0, {
+ value: 'en-US',
+ writable: true,
+ enumerable: true,
+ configurable: true,
+});
+
+result = Intl.getCanonicalLocales(locales);
+
+verifyProperty(result, 1, {
+ value: 'fr',
+ writable: true,
+ enumerable: true,
+ configurable: true,
+});
+
+result = Intl.getCanonicalLocales(locales);
+
+verifyProperty(result, "length", {
+ value: 2,
+ writable: true,
+ enumerable: false,
+ configurable: false,
+});
+
+result.length = 42;
+assert.sameValue(result.length, 42);
+
+assert.throws(RangeError, function() {
+ result.length = "Leo";
+}, "a non-numeric value can't be set to result.length");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/shell.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/to-string.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/to-string.js
new file mode 100644
index 0000000000..464a4cb03b
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/to-string.js
@@ -0,0 +1,22 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Test Intl.getCanonicalLocales.name for step 7.c.iii
+info: |
+ 9.2.1 CanonicalizeLocaleList (locales)
+ 7. Repeat, while k < len.
+ c. If kPresent is true, then
+ iii. Let tag be ? ToString(kValue).
+includes: [compareArray.js]
+---*/
+
+var locales = {
+ '0': { toString: function() { locales[1] = 'pt-BR'; return 'en-US'; }},
+ length: 2
+};
+
+assert.compareArray(Intl.getCanonicalLocales(locales), [ "en-US", "pt-BR" ]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js
new file mode 100644
index 0000000000..c6717a364b
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test canonicalisation within transformed extension subtags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+includes: [testIntl.js]
+---*/
+
+const testData = {
+ // Variant subtags are alphabetically ordered.
+ "sl-t-sl-rozaj-biske-1994": "sl-t-sl-1994-biske-rozaj",
+
+ // tfield subtags are alphabetically ordered.
+ // (Also tests subtag case normalisation.)
+ "DE-T-M0-DIN-K0-QWERTZ": "de-t-k0-qwertz-m0-din",
+
+ // "true" tvalue subtags aren't removed.
+ // (UTS 35 version 36, §3.2.1 claims otherwise, but tkey must be followed by
+ // tvalue, so that's likely a spec bug in UTS 35.)
+ "en-t-m0-true": "en-t-m0-true",
+
+ // tlang subtags are canonicalised.
+ "en-t-iw": "en-t-he",
+
+ // Deprecated tvalue subtags are replaced by their preferred value.
+ "und-Latn-t-und-hani-m0-names": "und-Latn-t-und-hani-m0-prprname",
+};
+
+for (let [tag, canonical] of Object.entries(testData)) {
+ // Make sure the test data is correct.
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-invalid.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-invalid.js
new file mode 100644
index 0000000000..2a278ce2b3
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-invalid.js
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ A RangeError is thrown when a language tag includes an invalid transformed extension subtag.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ ...
+
+includes: [testIntl.js]
+---*/
+
+const invalid = [
+ // empty
+ "en-t",
+ "en-t-a",
+ "en-t-x",
+ "en-t-0",
+
+ // incomplete
+ "en-t-",
+ "en-t-en-",
+ "en-t-0x-",
+
+ // tlang: unicode_language_subtag must be 2-3 or 5-8 characters and mustn't
+ // contain extlang subtags.
+ "en-t-root",
+ "en-t-abcdefghi",
+ "en-t-ar-aao",
+
+ // tlang: unicode_script_subtag must be 4 alphabetical characters, can't
+ // be repeated.
+ "en-t-en-lat0",
+ "en-t-en-latn-latn",
+
+ // tlang: unicode_region_subtag must either be 2 alpha characters or a three
+ // digit code.
+ "en-t-en-0",
+ "en-t-en-00",
+ "en-t-en-0x",
+ "en-t-en-x0",
+ "en-t-en-latn-0",
+ "en-t-en-latn-00",
+ "en-t-en-latn-xyz",
+
+ // tlang: unicode_variant_subtag is either 5-8 alphanum characters or 4
+ // characters starting with a digit.
+ "en-t-en-abcdefghi",
+ "en-t-en-latn-gb-ab",
+ "en-t-en-latn-gb-abc",
+ "en-t-en-latn-gb-abcd",
+ "en-t-en-latn-gb-abcdefghi",
+
+ // tkey must be followed by tvalue.
+ "en-t-d0",
+ "en-t-d0-m0",
+ "en-t-d0-x-private",
+];
+
+for (let tag of invalid) {
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a structurally valid language tag.");
+
+ assert.throws(RangeError, () => Intl.getCanonicalLocales(tag), `${tag}`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-valid.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-valid.js
new file mode 100644
index 0000000000..6668b94ad8
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/transformed-ext-valid.js
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ No RangeError is thrown when a language tag includes a valid transformed extension subtag.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+includes: [testIntl.js]
+---*/
+
+const valid = [
+ // tlang with unicode_language_subtag.
+ "en-t-en",
+
+ // tlang with unicode_script_subtag.
+ "en-t-en-latn",
+
+ // tlang with unicode_region_subtag.
+ "en-t-en-ca",
+
+ // tlang with unicode_script_subtag and unicode_region_subtag.
+ "en-t-en-latn-ca",
+
+ // tlang with unicode_variant_subtag.
+ "en-t-en-emodeng",
+
+ // tlang with unicode_script_subtag and unicode_variant_subtag.
+ "en-t-en-latn-emodeng",
+
+ // tlang with unicode_script_subtag and unicode_variant_subtag.
+ "en-t-en-ca-emodeng",
+
+ // tlang with unicode_script_subtag, unicode_region_subtag, and unicode_variant_subtag.
+ "en-t-en-latn-ca-emodeng",
+
+ // No tlang. (Must contain at least one tfield.)
+ "en-t-d0-ascii",
+];
+
+const extraFields = [
+ // No extra tfield
+ "",
+
+ // tfield with a tvalue consisting of a single subtag.
+ "-i0-handwrit",
+
+ // tfield with a tvalue consisting of two subtags.
+ "-s0-accents-publish",
+];
+
+for (let tag of valid) {
+ for (let extra of extraFields) {
+ let actualTag = tag + extra;
+
+ // Make sure the test data is correct.
+ assert(isCanonicalizedStructurallyValidLanguageTag(actualTag),
+ "\"" + actualTag + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(actualTag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], actualTag);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-calendar.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-calendar.js
new file mode 100644
index 0000000000..736b8e7013
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-calendar.js
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "ca" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+includes: [testIntl.js]
+---*/
+
+// <key name="ca" [...] alias="calendar">
+const testData = {
+ // <type name="ethioaa" [...] alias="ethiopic-amete-alem"/>
+ "ethiopic-amete-alem": "ethioaa",
+
+ // <type name="islamic-civil" [...] />
+ // <type name="islamicc" [...] deprecated="true" preferred="islamic-civil" alias="islamic-civil"/>
+ //
+ // "name" and "alias" for "islamic-civil" don't quite match of what's spec'ed in UTS 35, §3.2.1.
+ // Specifically following §3.2.1 to the letter means "islamicc" is the canonical value whereas
+ // "islamic-civil" is an alias value. Assume the definitions in
+ // https://unicode.org/reports/tr35/#Unicode_Locale_Extension_Data_Files overrule UTS 35, §3.2.1.
+ "islamicc": "islamic-civil",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ let tag = "und-u-ca-" + alias;
+ let canonical = "und-u-ca-" + name;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-col-strength.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-col-strength.js
new file mode 100644
index 0000000000..48c033d7e1
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-col-strength.js
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "ks" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+includes: [testIntl.js]
+---*/
+
+// <key name="ks" [...] alias="colStrength">/
+const testData = {
+ // <type name="level1" [...] alias="primary"/>
+ "primary": "level1",
+
+ // "secondary" doesn't match |uvalue|, so we can skip it.
+ // <type name="level2" [...] alias="secondary"/>
+ // "secondary": "level2",
+
+ // <type name="level3" [...] alias="tertiary"/>
+ "tertiary": "level3",
+
+ // Neither "quaternary" nor "quarternary" match |uvalue|, so we can skip them.
+ // <type name="level4" [...] alias="quaternary quarternary"/>
+ // "quaternary": "level4",
+ // "quarternary": "level4",
+
+ // "identical" doesn't match |uvalue|, so we can skip it.
+ // <type name="identic" [...] alias="identical"/>
+ // "identical": "identic",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ let tag = "und-u-ks-" + alias;
+ let canonical = "und-u-ks-" + name;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-measurement-system.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-measurement-system.js
new file mode 100644
index 0000000000..28c587155b
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-measurement-system.js
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "ms" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+includes: [testIntl.js]
+---*/
+
+// <key name="ms" [...] alias="measure" since="28">
+const testData = {
+ // <type name="uksystem" [...] alias="imperial" since="28" />
+ "imperial": "uksystem",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ let tag = "und-u-ms-" + alias;
+ let canonical = "und-u-ms-" + name;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-region.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-region.js
new file mode 100644
index 0000000000..34e1e95082
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-region.js
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "rg" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+
+ Replace aliases in special key values:
+ If there is an 'sd' or 'rg' key, replace any subdivision alias in its value in the same way,
+ using subdivisionAlias data.
+includes: [testIntl.js]
+---*/
+
+const testData = {
+ // <subdivisionAlias type="no23" replacement="no50" reason="deprecated"/>
+ "no23": "no50",
+
+ // <subdivisionAlias type="cn11" replacement="cnbj" reason="deprecated"/>
+ "cn11": "cnbj",
+
+ // <subdivisionAlias type="cz10a" replacement="cz110" reason="deprecated"/>
+ "cz10a": "cz110",
+
+ // <subdivisionAlias type="fra" replacement="frges" reason="deprecated"/>
+ "fra": "frges",
+
+ // <subdivisionAlias type="frg" replacement="frges" reason="deprecated"/>
+ "frg": "frges",
+
+ // <subdivisionAlias type="lud" replacement="lucl ludi lurd luvd luwi" reason="deprecated"/>
+ "lud": "lucl",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ let tag = "und-u-rg-" + alias;
+ let canonical = "und-u-rg-" + name;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-subdivision.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-subdivision.js
new file mode 100644
index 0000000000..d7f9f6ff4f
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-subdivision.js
@@ -0,0 +1,74 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "sd" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+
+ Replace aliases in special key values:
+ If there is an 'sd' or 'rg' key, replace any subdivision alias in its value in the same way,
+ using subdivisionAlias data.
+includes: [testIntl.js]
+---*/
+
+const testData = {
+ // <subdivisionAlias type="no23" replacement="no50" reason="deprecated"/>
+ "no23": "no50",
+
+ // <subdivisionAlias type="cn11" replacement="cnbj" reason="deprecated"/>
+ "cn11": "cnbj",
+
+ // <subdivisionAlias type="cz10a" replacement="cz110" reason="deprecated"/>
+ "cz10a": "cz110",
+
+ // <subdivisionAlias type="fra" replacement="frges" reason="deprecated"/>
+ "fra": "frges",
+
+ // <subdivisionAlias type="frg" replacement="frges" reason="deprecated"/>
+ "frg": "frges",
+
+ // <subdivisionAlias type="lud" replacement="lucl ludi lurd luvd luwi" reason="deprecated"/>
+ "lud": "lucl",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ // Subdivision codes should always have a matching region subtag. This
+ // shouldn't actually matter for canonicalisation, but let's not push our
+ // luck and instead keep the language tag 'valid' per UTS 35, §3.6.5.
+ let region = name.substring(0, 2).toUpperCase();
+
+ let tag = `und-${region}-u-sd-${alias}`;
+ let canonical = `und-${region}-u-sd-${name}`;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-timezone.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-timezone.js
new file mode 100644
index 0000000000..8a6a780c83
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-timezone.js
@@ -0,0 +1,74 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtag canonicalisation for the "tz" extension key.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+includes: [testIntl.js]
+---*/
+
+// <key name="tz" [...] alias="timezone">
+const testData = {
+ // Similar to the "ca" extension key, assume "preferred" holds the canonical
+ // value and "name" the alias value.
+
+ // <type name="cnckg" [...] deprecated="true" preferred="cnsha"/>
+ "cnckg": "cnsha",
+
+ // NB: "Eire" matches the |uvalue| production.
+ // <type name="iedub" [...] alias="Europe/Dublin Eire"/>
+ "eire": "iedub",
+
+ // NB: "EST" matches the |uvalue| production.
+ // <type name="utcw05" [...] alias="Etc/GMT+5 EST"/>
+ "est": "utcw05",
+
+ // NB: "GMT0" matches the |uvalue| production.
+ // <type name="gmt" [...] alias="Etc/GMT Etc/GMT+0 Etc/GMT-0 Etc/GMT0 Etc/Greenwich GMT GMT+0 GMT-0 GMT0 Greenwich"/>
+ "gmt0": "gmt",
+
+ // NB: "UCT" matches the |uvalue| production.
+ // <type name="utc" [...] alias="Etc/UTC Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu"/>
+ "uct": "utc",
+
+ // NB: "Zulu" matches the |uvalue| production.
+ // <type name="utc" [...] alias="Etc/UTC Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu"/>
+ "zulu": "utc",
+};
+
+for (let [alias, name] of Object.entries(testData)) {
+ let tag = "und-u-tz-" + alias;
+ let canonical = "und-u-tz-" + name;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-yes-to-true.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-yes-to-true.js
new file mode 100644
index 0000000000..7ef23a3586
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-canonicalize-yes-to-true.js
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ "kb", "kc", "kh", "kk", and "kn" Unicode extension keys canonicalise "yes" to "true".
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Use the bcp47 data to replace keys, types, tfields, and tvalues by their canonical forms.
+ See Section 3.6.4 U Extension Data Files) and Section 3.7.1 T Extension Data Files. The
+ aliases are in the alias attribute value, while the canonical is in the name attribute value.
+
+ UTS 35, §3.2.1 Canonical Unicode Locale Identifiers
+ Any type or tfield value "true" is removed.
+includes: [testIntl.js]
+---*/
+
+const unicodeKeys = [
+ // <key name="kb" [...] alias="colBackwards">
+ // <type name="true" [...] alias="yes"/>
+ "kb",
+
+ // <key name="kc" [...] alias="colCaseLevel">
+ // <type name="true" [...] alias="yes"/>
+ "kc",
+
+ // <key name="kh" [...] alias="colBackwards">
+ // <type name="true" [...] alias="yes"/>
+ "kh",
+
+ // <key name="kh" [...] alias="colHiraganaQuaternary">
+ // <type name="true" [...] alias="yes"/>
+ "kk",
+
+ // <key name="kn" [...] alias="colNumeric">
+ // <type name="true" [...] alias="yes"/>
+ "kn",
+];
+
+for (let key of unicodeKeys) {
+ let tag = `und-u-${key}-yes`;
+ let canonical = `und-u-${key}`;
+
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(tag), false,
+ "\"" + tag + "\" isn't a canonical language tag.");
+ assert(isCanonicalizedStructurallyValidLanguageTag(canonical),
+ "\"" + canonical + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], canonical);
+}
+
+// Test some other Unicode extension keys which don't contain an alias entry to
+// canonicalise "yes" to "true".
+const otherUnicodeKeys = [
+ "ka", "kf", "kr", "ks", "kv",
+];
+
+for (let key of otherUnicodeKeys) {
+ let tag = `und-u-${key}-yes`;
+
+ // Make sure the test data is correct.
+ assert(isCanonicalizedStructurallyValidLanguageTag(tag),
+ "\"" + tag + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(tag);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], tag);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js
new file mode 100644
index 0000000000..9271e01f7a
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: >
+ Test Unicode extension subtags where the ukey subtag contains a digit.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+
+ 9.2.1 CanonicalizeLocaleList (locales)
+ ...
+ 7. Repeat, while k < len
+ ...
+ c. If kPresent is true, then
+ ...
+ v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag).
+ ...
+
+includes: [testIntl.js]
+---*/
+
+// Unicode locale extension sequences don't allow keys with a digit as their
+// second character.
+const invalidCases = [
+ "en-u-c0",
+ "en-u-00",
+];
+
+// The first character is allowed to be a digit.
+const validCases = [
+ "en-u-0c",
+];
+
+for (let invalid of invalidCases) {
+ // Make sure the test data is correct.
+ assert.sameValue(isCanonicalizedStructurallyValidLanguageTag(invalid), false,
+ "\"" + invalid + "\" isn't a structurally valid language tag.");
+
+ assert.throws(RangeError, () => Intl.getCanonicalLocales(invalid));
+}
+
+for (let valid of validCases) {
+ // Make sure the test data is correct.
+ assert(isCanonicalizedStructurallyValidLanguageTag(valid),
+ "\"" + valid + "\" is a canonical and structurally valid language tag.");
+
+ let result = Intl.getCanonicalLocales(valid);
+ assert.sameValue(result.length, 1);
+ assert.sameValue(result[0], valid);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/getCanonicalLocales/weird-cases.js b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/weird-cases.js
new file mode 100644
index 0000000000..e7b680b570
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/getCanonicalLocales/weird-cases.js
@@ -0,0 +1,26 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-intl.getcanonicallocales
+description: Tests the getCanonicalLocales function for weird tags.
+info: |
+ 8.2.1 Intl.getCanonicalLocales (locales)
+ 1. Let ll be ? CanonicalizeLocaleList(locales).
+ 2. Return CreateArrayFromList(ll).
+includes: [compareArray.js]
+---*/
+
+var weirdCases =
+ [
+ "en-x-u-foo",
+ "en-a-bar-x-u-foo",
+ "en-x-u-foo-a-bar",
+ "en-a-bar-u-baz-x-u-foo",
+ ];
+
+weirdCases.forEach(function (weird) {
+ assert.compareArray(Intl.getCanonicalLocales(weird), [weird]);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/shell.js b/js/src/tests/test262/intl402/Intl/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/browser.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/builtin.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/builtin.js
new file mode 100644
index 0000000000..8689ef54af
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/builtin.js
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Intl.supportedValuesOf is a built-in function object..
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 18 ECMAScript Standard Built-in Objects:
+ Unless specified otherwise, a built-in object that is callable as a function
+ is a built-in function object with the characteristics described in 10.3.
+ Unless specified otherwise, the [[Extensible]] internal slot of a built-in
+ object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in
+ constructor has the Function prototype object, which is the initial value
+ of the expression Function.prototype (20.2.3), as the value of its
+ [[Prototype]] internal slot.
+
+ Built-in function objects that are not identified as constructors do not
+ implement the [[Construct]] internal method unless otherwise specified in
+ the description of a particular function.
+includes: [isConstructor.js]
+features: [Intl-enumeration, Reflect.construct]
+---*/
+
+assert.sameValue(typeof Intl.supportedValuesOf, "function",
+ "Intl.supportedValuesOf is a function");
+
+assert(!Object.prototype.hasOwnProperty.call(Intl.supportedValuesOf, "prototype"),
+ "Intl.supportedValuesOf doesn't have an own 'prototype' property");
+
+assert(Object.isExtensible(Intl.supportedValuesOf),
+ "Built-in objects must be extensible");
+
+assert.sameValue(Object.getPrototypeOf(Intl.supportedValuesOf), Function.prototype,
+ "[[Prototype]] of Intl.supportedValuesOf is Function.prototype");
+
+assert(!isConstructor(Intl.supportedValuesOf),
+ "Intl.supportedValuesOf not a constructor function");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DateTimeFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DateTimeFormat.js
new file mode 100644
index 0000000000..9cbaa39c06
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DateTimeFormat.js
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "calendar" values can be used with DateTimeFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ 2. If key is "calendar", then
+ a. Let list be ! AvailableCalendars( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCalendars ( )
+ The AvailableCalendars abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique calendar types identifying the
+ calendars for which the implementation provides the functionality of
+ Intl.DateTimeFormat objects. The list must include "gregory".
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const calendars = Intl.supportedValuesOf("calendar");
+
+for (let calendar of calendars) {
+ let obj = new Intl.DateTimeFormat("en", {calendar});
+ assert.sameValue(obj.resolvedOptions().calendar, calendar,
+ `${calendar} is supported by DateTimeFormat`);
+}
+
+for (let calendar of allCalendars()) {
+ let obj = new Intl.DateTimeFormat("en", {calendar});
+ if (obj.resolvedOptions().calendar === calendar) {
+ assert(calendars.includes(calendar),
+ `${calendar} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!calendars.includes(calendar),
+ `${calendar} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DisplayNames.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DisplayNames.js
new file mode 100644
index 0000000000..b1c34fd51c
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars-accepted-by-DisplayNames.js
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "calendar" values can be used with DisplayNames.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ 2. If key is "calendar", then
+ a. Let list be ! AvailableCalendars( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCalendars ( )
+ The AvailableCalendars abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique calendar types identifying the
+ calendars for which the implementation provides the functionality of
+ Intl.DateTimeFormat objects. The list must include "gregory".
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Intl.DisplayNames-v2, Array.prototype.includes]
+---*/
+
+const calendars = Intl.supportedValuesOf("calendar");
+
+const obj = new Intl.DisplayNames("en", {type: "calendar", fallback: "none"});
+
+for (let calendar of calendars) {
+ assert.sameValue(typeof obj.of(calendar), "string",
+ `${calendar} is supported by DisplayNames`);
+}
+
+for (let calendar of allCalendars()) {
+ if (typeof obj.of(calendar) === "string") {
+ assert(calendars.includes(calendar),
+ `${calendar} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!calendars.includes(calendar),
+ `${calendar} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars.js
new file mode 100644
index 0000000000..4de1a5e689
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/calendars.js
@@ -0,0 +1,56 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "calendar" values are sorted, unique, and match the type production.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ 2. If key is "calendar", then
+ a. Let list be ! AvailableCalendars( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCalendars ( )
+ The AvailableCalendars abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique calendar types identifying the
+ calendars for which the implementation provides the functionality of
+ Intl.DateTimeFormat objects. The list must include "gregory".
+includes: [compareArray.js]
+features: [Intl-enumeration, Intl.Locale, Array.prototype.includes]
+---*/
+
+const calendars = Intl.supportedValuesOf("calendar");
+
+assert(Array.isArray(calendars), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(calendars), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherCalendars = Intl.supportedValuesOf("calendar");
+assert.notSameValue(otherCalendars, calendars,
+ "Returns a new array object for each call.");
+
+assert.compareArray(calendars, otherCalendars.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(calendars).size, calendars.length,
+ "The array doesn't contain duplicates.");
+
+// https://unicode.org/reports/tr35/tr35.html#Unicode_locale_identifier
+const typeRE = /^[a-z0-9]{3,8}(-[a-z0-9]{3,8})*$/;
+for (let calendar of calendars) {
+ assert(typeRE.test(calendar), `${calendar} matches the 'type' production`);
+}
+
+for (let calendar of calendars) {
+ assert.sameValue(new Intl.Locale("und", {calendar}).calendar, calendar,
+ `${calendar} is canonicalised`);
+}
+
+assert(calendars.includes("gregory"), "Includes the Gregorian calendar.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/coerced-to-string.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/coerced-to-string.js
new file mode 100644
index 0000000000..b5354265b9
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/coerced-to-string.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Input key is coerced with ToString.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ 2. If key is "calendar", then
+ a. Let list be ! AvailableCalendars( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+includes: [compareArray.js]
+features: [Intl-enumeration]
+---*/
+
+const calendars = Intl.supportedValuesOf("calendar");
+
+// ToString on a String object.
+assert.compareArray(Intl.supportedValuesOf(new String("calendar")), calendars);
+
+// ToString on a plain object.
+let obj = {
+ toString() {
+ return "calendar";
+ }
+};
+assert.compareArray(Intl.supportedValuesOf(obj), calendars);
+
+// ToString() of a symbol throws a TypeError.
+assert.throws(TypeError, function() {
+ Intl.supportedValuesOf(Symbol());
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations-accepted-by-Collator.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations-accepted-by-Collator.js
new file mode 100644
index 0000000000..ee4413581b
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations-accepted-by-Collator.js
@@ -0,0 +1,83 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "collation" values can be used with Collator.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 3. Else if key is "collation", then
+ a. Let list be ! AvailableCollations( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCollations ( )
+ The AvailableCollations abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique collation types identifying the
+ collations for which the implementation provides the functionality of
+ Intl.Collator objects.
+includes: [testIntl.js]
+locale: [en, ar, de, es, ko, ln, si, sv, zh]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const collations = Intl.supportedValuesOf("collation");
+
+// Not all locales support all possible collations, so test the minimal set to
+// cover all supported collations.
+//
+// The list of all collations can be derived from
+// <https://github.com/unicode-org/cldr/blob/master/common/bcp47/collation.xml>.
+//
+// Note: "standard" and "search" are explicitly disallowed by Intl.Collator.
+const locales = [
+ "en", // ducet, emoji, eor
+ "ar", // compat
+ "de", // phonebk
+ "es", // trad
+ "hi", // direct
+ "ko", // searchjl
+ "ln", // phonetic
+ "si", // dict
+ "sv", // reformed
+ "zh", // big5han, gb2312, pinyin, stroke, unihan, zhuyin
+];
+
+for (let collation of collations) {
+ let supported = false;
+ for (let locale of locales) {
+ let obj = new Intl.Collator(locale, {collation});
+ if (obj.resolvedOptions().collation === collation) {
+ supported = true;
+ break;
+ }
+ }
+
+ assert(supported, `${collation} is supported by Collator`);
+}
+
+for (let collation of allCollations()) {
+ let supported = false;
+ for (let locale of locales) {
+ let obj = new Intl.Collator(locale, {collation});
+ if (obj.resolvedOptions().collation === collation) {
+ supported = true;
+ break;
+ }
+ }
+
+ if (supported) {
+ assert(collations.includes(collation),
+ `${collation} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!collations.includes(collation),
+ `${collation} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations.js
new file mode 100644
index 0000000000..372f84c7bf
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/collations.js
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "collation" values are sorted, unique, and match the type production.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 3. Else if key is "collation", then
+ a. Let list be ! AvailableCollations( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCollations ( )
+ The AvailableCollations abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique collation types identifying the
+ collations for which the implementation provides the functionality of
+ Intl.Collator objects.
+includes: [compareArray.js]
+features: [Intl-enumeration, Intl.Locale, Array.prototype.includes]
+---*/
+
+const collations = Intl.supportedValuesOf("collation");
+
+assert(Array.isArray(collations), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(collations), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherCollations = Intl.supportedValuesOf("collation");
+assert.notSameValue(otherCollations, collations,
+ "Returns a new array object for each call.");
+
+assert.compareArray(collations, otherCollations.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(collations).size, collations.length,
+ "The array doesn't contain duplicates.");
+
+// https://unicode.org/reports/tr35/tr35.html#Unicode_locale_identifier
+const typeRE = /^[a-z0-9]{3,8}(-[a-z0-9]{3,8})*$/;
+for (let collation of collations) {
+ assert(typeRE.test(collation), `${collation} matches the 'type' production`);
+}
+
+for (let collation of collations) {
+ assert.sameValue(new Intl.Locale("und", {collation}).collation, collation,
+ `${collation} is canonicalised`);
+}
+
+assert(!collations.includes("standard"), "Mustn't include the 'standard' collation type.");
+assert(!collations.includes("search"), "Mustn't include the 'search' collation type.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-DisplayNames.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-DisplayNames.js
new file mode 100644
index 0000000000..cccc756b9f
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-DisplayNames.js
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "currency" values can be used with DisplayNames.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 4. Else if key is "currency", then
+ a. Let list be ! AvailableCurrencies( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCurrencies ( )
+ The AvailableCurrencies abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique, well-formed, and upper case
+ canonicalized 3-letter ISO 4217 currency codes, identifying the currencies
+ for which the implementation provides the functionality of Intl.DisplayNames
+ and Intl.NumberFormat objects.
+locale: [en]
+features: [Intl-enumeration, Intl.DisplayNames, Array.prototype.includes]
+---*/
+
+const currencies = Intl.supportedValuesOf("currency");
+
+const obj = new Intl.DisplayNames("en", {type: "currency", fallback: "none"});
+
+for (let currency of currencies) {
+ assert.sameValue(typeof obj.of(currency), "string",
+ `${currency} is supported by DisplayNames`);
+}
+
+for (let i = 0x41; i <= 0x5A; ++i) {
+ for (let j = 0x41; j <= 0x5A; ++j) {
+ for (let k = 0x41; k <= 0x5A; ++k) {
+ let currency = String.fromCharCode(i, j, k);
+ if (typeof obj.of(currency) === "string") {
+ assert(currencies.includes(currency),
+ `${currency} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!currencies.includes(currency),
+ `${currency} not supported but returned by supportedValuesOf`);
+ }
+ }
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-NumberFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-NumberFormat.js
new file mode 100644
index 0000000000..089d0dd322
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies-accepted-by-NumberFormat.js
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "currency" values can be used with NumberFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 4. Else if key is "currency", then
+ a. Let list be ! AvailableCurrencies( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCurrencies ( )
+ The AvailableCurrencies abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique, well-formed, and upper case
+ canonicalized 3-letter ISO 4217 currency codes, identifying the currencies
+ for which the implementation provides the functionality of Intl.DisplayNames
+ and Intl.NumberFormat objects.
+locale: [en]
+features: [Intl-enumeration]
+---*/
+
+const currencies = Intl.supportedValuesOf("currency");
+
+for (let currency of currencies) {
+ let obj = new Intl.NumberFormat("en", {style: "currency", currency});
+ assert.sameValue(obj.resolvedOptions().currency, currency,
+ `${currency} is supported by NumberFormat`);
+}
+
+// Note: We can't test that additional currency values not present in |currencies|
+// aren't supported by Intl.NumberFormat, because PartitionNumberPattern defaults
+// to using the currency code itself when the currency is unsupported:
+//
+// PartitionNumberPattern, step 8.k.iii:
+// Let cd be an ILD String value representing currency after x in currencyDisplay form,
+// which may depend on x in languages having different plural forms. If the
+// implementation does not have such a representation of currency, use currency itself.
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies.js
new file mode 100644
index 0000000000..467ee39ca1
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/currencies.js
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "currency" values are sorted, unique, and upper-case canonicalised.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 4. Else if key is "currency", then
+ a. Let list be ! AvailableCurrencies( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableCurrencies ( )
+ The AvailableCurrencies abstract operation returns a List, ordered as if an
+ Array of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains unique, well-formed, and upper case
+ canonicalized 3-letter ISO 4217 currency codes, identifying the currencies
+ for which the implementation provides the functionality of Intl.DisplayNames
+ and Intl.NumberFormat objects.
+includes: [compareArray.js]
+features: [Intl-enumeration]
+---*/
+
+const currencies = Intl.supportedValuesOf("currency");
+
+assert(Array.isArray(currencies), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(currencies), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherCurrencies = Intl.supportedValuesOf("currency");
+assert.notSameValue(otherCurrencies, currencies,
+ "Returns a new array object for each call.");
+
+assert.compareArray(currencies, otherCurrencies.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(currencies).size, currencies.length,
+ "The array doesn't contain duplicates.");
+
+const codeRE = /^[A-Z]{3}$/;
+for (let currency of currencies) {
+ assert(codeRE.test(currency), `${currency} is a 3-letter ISO 4217 currency code`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/invalid-key.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/invalid-key.js
new file mode 100644
index 0000000000..07202b4b5d
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/invalid-key.js
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Intl.supportedValuesOf throws a RangeError if the key is invalid.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 8. Else,
+ a. Throw a RangeError exception.
+ ...
+features: [Intl-enumeration]
+---*/
+
+const invalidKeys = [
+ // Empty string is invalid.
+ "",
+
+ // Various unsupported keys.
+ "hourCycle", "locale", "language", "script", "region",
+
+ // Plural form of supported keys not valid.
+ "calendars", "collations", "currencies", "numberingSystems", "timeZones", "units",
+
+ // Wrong case for supported keys.
+ "CALENDAR", "Collation", "Currency", "numberingsystem", "timezone", "UNIT",
+
+ // NUL character must be handled correctly.
+ "calendar\0",
+
+ // Non-string cases.
+ undefined, null, false, true, NaN, 0, Math.PI, 123n, {}, [],
+];
+
+for (let key of invalidKeys) {
+ assert.throws(RangeError, function() {
+ Intl.supportedValuesOf(key);
+ }, "key: " + key);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/length.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/length.js
new file mode 100644
index 0000000000..39a5d577f0
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/length.js
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Intl.supportedValuesOf.length value and descriptor.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 18 ECMAScript Standard Built-in Objects:
+ Every built-in function object, including constructors, has a "length"
+ property whose value is a non-negative integral Number. Unless otherwise
+ specified, this value is equal to the number of required parameters shown in
+ the subclause heading for the function description. Optional parameters and
+ rest parameters are not included in the parameter 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]
+features: [Intl-enumeration]
+---*/
+
+verifyProperty(Intl.supportedValuesOf, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/name.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/name.js
new file mode 100644
index 0000000000..c8838bb249
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/name.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Intl.supportedValuesOf.name value and descriptor.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 18 ECMAScript Standard Built-in Objects:
+ Every built-in function object, including constructors, has a "name"
+ property whose value is a String. Unless otherwise specified, this value is
+ the name that is given to the function in this specification. Functions that
+ are identified as anonymous functions use the empty String as the value of
+ the "name" property. For functions that are specified as properties of
+ objects, the name value is the property name string used to access the
+ function.
+
+ Unless otherwise specified, the "name" property of a built-in function object
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Intl-enumeration]
+---*/
+
+verifyProperty(Intl.supportedValuesOf, "name", {
+ value: "supportedValuesOf",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-DateTimeFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-DateTimeFormat.js
new file mode 100644
index 0000000000..71c89eaa97
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-DateTimeFormat.js
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "numberingSystem" values can be used with DateTimeFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 5. Else if key is "numberingSystem", then
+ a. Let list be ! AvailableNumberingSystems( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableNumberingSystems ( )
+ The AvailableNumberingSystems abstract operation returns a List, ordered as
+ if an Array of the same values had been sorted using %Array.prototype.sort%
+ using undefined as comparefn, that contains unique numbering systems
+ identifiers identifying the numbering systems for which the implementation
+ provides the functionality of Intl.DateTimeFormat, Intl.NumberFormat, and
+ Intl.RelativeTimeFormat objects. The list must include the Numbering System
+ value of every row of Table 4, except the header row.
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const numberingSystems = Intl.supportedValuesOf("numberingSystem");
+
+for (let numberingSystem of numberingSystems) {
+ let obj = new Intl.DateTimeFormat("en", {numberingSystem});
+ assert.sameValue(obj.resolvedOptions().numberingSystem, numberingSystem,
+ `${numberingSystem} is supported by DateTimeFormat`);
+}
+
+for (let numberingSystem of allNumberingSystems()) {
+ let obj = new Intl.DateTimeFormat("en", {numberingSystem});
+ if (obj.resolvedOptions().numberingSystem === numberingSystem) {
+ assert(numberingSystems.includes(numberingSystem),
+ `${numberingSystem} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!numberingSystems.includes(numberingSystem),
+ `${numberingSystem} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-NumberFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-NumberFormat.js
new file mode 100644
index 0000000000..877d28368c
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-NumberFormat.js
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "numberingSystem" values can be used with NumberFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 5. Else if key is "numberingSystem", then
+ a. Let list be ! AvailableNumberingSystems( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableNumberingSystems ( )
+ The AvailableNumberingSystems abstract operation returns a List, ordered as
+ if an Array of the same values had been sorted using %Array.prototype.sort%
+ using undefined as comparefn, that contains unique numbering systems
+ identifiers identifying the numbering systems for which the implementation
+ provides the functionality of Intl.DateTimeFormat, Intl.NumberFormat, and
+ Intl.RelativeTimeFormat objects. The list must include the Numbering System
+ value of every row of Table 4, except the header row.
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const numberingSystems = Intl.supportedValuesOf("numberingSystem");
+
+for (let numberingSystem of numberingSystems) {
+ let obj = new Intl.NumberFormat("en", {numberingSystem});
+ assert.sameValue(obj.resolvedOptions().numberingSystem, numberingSystem,
+ `${numberingSystem} is supported by NumberFormat`);
+}
+
+for (let numberingSystem of allNumberingSystems()) {
+ let obj = new Intl.NumberFormat("en", {numberingSystem});
+ if (obj.resolvedOptions().numberingSystem === numberingSystem) {
+ assert(numberingSystems.includes(numberingSystem),
+ `${numberingSystem} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!numberingSystems.includes(numberingSystem),
+ `${numberingSystem} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-RelativeTimeFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-RelativeTimeFormat.js
new file mode 100644
index 0000000000..423a3ae3dc
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-accepted-by-RelativeTimeFormat.js
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "numberingSystem" values can be used with RelativeTimeFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 5. Else if key is "numberingSystem", then
+ a. Let list be ! AvailableNumberingSystems( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableNumberingSystems ( )
+ The AvailableNumberingSystems abstract operation returns a List, ordered as
+ if an Array of the same values had been sorted using %Array.prototype.sort%
+ using undefined as comparefn, that contains unique numbering systems
+ identifiers identifying the numbering systems for which the implementation
+ provides the functionality of Intl.DateTimeFormat, Intl.NumberFormat, and
+ Intl.RelativeTimeFormat objects. The list must include the Numbering System
+ value of every row of Table 4, except the header row.
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Intl.RelativeTimeFormat, Array.prototype.includes]
+---*/
+
+const numberingSystems = Intl.supportedValuesOf("numberingSystem");
+
+for (let numberingSystem of numberingSystems) {
+ let obj = new Intl.RelativeTimeFormat("en", {numberingSystem});
+ assert.sameValue(obj.resolvedOptions().numberingSystem, numberingSystem,
+ `${numberingSystem} is supported by RelativeTimeFormat`);
+}
+
+for (let numberingSystem of allNumberingSystems()) {
+ let obj = new Intl.RelativeTimeFormat("en", {numberingSystem});
+ if (obj.resolvedOptions().numberingSystem === numberingSystem) {
+ assert(numberingSystems.includes(numberingSystem),
+ `${numberingSystem} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!numberingSystems.includes(numberingSystem),
+ `${numberingSystem} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-with-simple-digit-mappings.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-with-simple-digit-mappings.js
new file mode 100644
index 0000000000..0ff107c350
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems-with-simple-digit-mappings.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "numberingSystem" values contain all numbering systems with simple digit mappings.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 5. Else if key is "numberingSystem", then
+ a. Let list be ! AvailableNumberingSystems( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableNumberingSystems ( )
+ The AvailableNumberingSystems abstract operation returns a List, ordered as
+ if an Array of the same values had been sorted using %Array.prototype.sort%
+ using undefined as comparefn, that contains unique numbering systems
+ identifiers identifying the numbering systems for which the implementation
+ provides the functionality of Intl.DateTimeFormat, Intl.NumberFormat, and
+ Intl.RelativeTimeFormat objects. The list must include the Numbering System
+ value of every row of Table 4, except the header row.
+includes: [testIntl.js]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const numberingSystems = Intl.supportedValuesOf("numberingSystem");
+
+// Table 10: Numbering systems with simple digit mappings
+for (let numberingSystem of Object.keys(numberingSystemDigits)) {
+ assert(numberingSystems.includes(numberingSystem),
+ `${numberingSystem} with simple digit mappings is supported`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems.js
new file mode 100644
index 0000000000..cb02432cd7
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/numberingSystems.js
@@ -0,0 +1,57 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "numberingSystem" values are sorted, unique, and match the type production.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 5. Else if key is "numberingSystem", then
+ a. Let list be ! AvailableNumberingSystems( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableNumberingSystems ( )
+ The AvailableNumberingSystems abstract operation returns a List, ordered as
+ if an Array of the same values had been sorted using %Array.prototype.sort%
+ using undefined as comparefn, that contains unique numbering systems
+ identifiers identifying the numbering systems for which the implementation
+ provides the functionality of Intl.DateTimeFormat, Intl.NumberFormat, and
+ Intl.RelativeTimeFormat objects. The list must include the Numbering System
+ value of every row of Table 4, except the header row.
+includes: [compareArray.js]
+features: [Intl-enumeration, Intl.Locale]
+---*/
+
+const numberingSystems = Intl.supportedValuesOf("numberingSystem");
+
+assert(Array.isArray(numberingSystems), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(numberingSystems), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherNumberingSystems = Intl.supportedValuesOf("numberingSystem");
+assert.notSameValue(otherNumberingSystems, numberingSystems,
+ "Returns a new array object for each call.");
+
+assert.compareArray(numberingSystems, otherNumberingSystems.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(numberingSystems).size, numberingSystems.length,
+ "The array doesn't contain duplicates.");
+
+// https://unicode.org/reports/tr35/tr35.html#Unicode_locale_identifier
+const typeRE = /^[a-z0-9]{3,8}(-[a-z0-9]{3,8})*$/;
+for (let numberingSystem of numberingSystems) {
+ assert(typeRE.test(numberingSystem), `${numberingSystem} matches the 'type' production`);
+}
+
+for (let numberingSystem of numberingSystems) {
+ assert.sameValue(new Intl.Locale("und", {numberingSystem}).numberingSystem, numberingSystem,
+ `${numberingSystem} is canonicalised`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/prop-desc.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/prop-desc.js
new file mode 100644
index 0000000000..5722b8f3ac
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/prop-desc.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ Intl.supportedValuesOf property attributes.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 18 ECMAScript Standard Built-in Objects:
+ Every other data property described in clauses 19 through 28 and in Annex B.2
+ has the attributes { [[Writable]]: true, [[Enumerable]]: false,
+ [[Configurable]]: true } unless otherwise specified.
+includes: [propertyHelper.js]
+features: [Intl-enumeration]
+---*/
+
+verifyProperty(Intl, "supportedValuesOf", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/shell.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/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/Intl/supportedValuesOf/timeZones-accepted-by-DateTimeFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones-accepted-by-DateTimeFormat.js
new file mode 100644
index 0000000000..b2be51b737
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones-accepted-by-DateTimeFormat.js
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "timeZone" values can be used with DateTimeFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 6. Else if key is "timeZone", then
+ a. Let list be ! AvailableTimeZones( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableTimeZones ()
+ The AvailableTimeZones abstract operation returns a sorted List of supported
+ Zone and Link names in the IANA Time Zone Database. The following steps are
+ taken:
+
+ 1. Let names be a List of all supported Zone and Link names in the IANA Time
+ Zone Database.
+ 2. Let result be a new empty List.
+ 3. For each element name of names, do
+ a. Assert: ! IsValidTimeZoneName( name ) is true.
+ b. Let canonical be ! CanonicalizeTimeZoneName( name ).
+ c. If result does not contain an element equal to canonical, then
+ i. Append canonical to the end of result.
+ 4. Sort result in order as if an Array of the same values had been sorted using
+ %Array.prototype.sort% using undefined as comparefn.
+ 5. Return result.
+locale: [en]
+features: [Intl-enumeration]
+---*/
+
+const timeZones = Intl.supportedValuesOf("timeZone");
+
+for (let timeZone of timeZones) {
+ let obj = new Intl.DateTimeFormat("en", {timeZone});
+ assert.sameValue(obj.resolvedOptions().timeZone, timeZone,
+ `${timeZone} is supported by DateTimeFormat`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones.js
new file mode 100644
index 0000000000..0f12d4c9e4
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/timeZones.js
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "timeZone" values are sorted, unique, and canonicalised.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 6. Else if key is "timeZone", then
+ a. Let list be ! AvailableTimeZones( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableTimeZones ()
+ The AvailableTimeZones abstract operation returns a sorted List of supported
+ Zone and Link names in the IANA Time Zone Database. The following steps are
+ taken:
+
+ 1. Let names be a List of all supported Zone and Link names in the IANA Time
+ Zone Database.
+ 2. Let result be a new empty List.
+ 3. For each element name of names, do
+ a. Assert: ! IsValidTimeZoneName( name ) is true.
+ b. Let canonical be ! CanonicalizeTimeZoneName( name ).
+ c. If result does not contain an element equal to canonical, then
+ i. Append canonical to the end of result.
+ 4. Sort result in order as if an Array of the same values had been sorted using
+ %Array.prototype.sort% using undefined as comparefn.
+ 5. Return result.
+includes: [compareArray.js, testIntl.js]
+features: [Intl-enumeration]
+---*/
+
+const timeZones = Intl.supportedValuesOf("timeZone");
+
+assert(Array.isArray(timeZones), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(timeZones), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherTimeZones = Intl.supportedValuesOf("timeZone");
+assert.notSameValue(otherTimeZones, timeZones,
+ "Returns a new array object for each call.");
+
+assert.compareArray(timeZones, otherTimeZones.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(timeZones).size, timeZones.length,
+ "The array doesn't contain duplicates.");
+
+for (let timeZone of timeZones) {
+ assert(isCanonicalizedStructurallyValidTimeZoneName(timeZone),
+ `${timeZone} is a canonicalised and structurally valid time zone name`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/units-accepted-by-NumberFormat.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/units-accepted-by-NumberFormat.js
new file mode 100644
index 0000000000..0132f569b2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/units-accepted-by-NumberFormat.js
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "unit" values can be used with NumberFormat.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 7. Else if key is "unit", then
+ a. Let list be ! AvailableUnits( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableUnits ( )
+ The AvailableUnits abstract operation returns a List, ordered as if an Array
+ of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains the unique values of simple unit
+ identifiers listed in every row of Table 1, except the header row.
+includes: [testIntl.js]
+locale: [en]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const units = Intl.supportedValuesOf("unit");
+
+for (let unit of units) {
+ let obj = new Intl.NumberFormat("en", {style: "unit", unit});
+ assert.sameValue(obj.resolvedOptions().unit, unit,
+ `${unit} is supported by NumberFormat`);
+}
+
+for (let unit of allSimpleSanctionedUnits()) {
+ let obj = new Intl.NumberFormat("en", {style: "unit", unit});
+ if (obj.resolvedOptions().unit === unit) {
+ assert(units.includes(unit),
+ `${unit} supported but not returned by supportedValuesOf`);
+ } else {
+ assert(!units.includes(unit),
+ `${unit} not supported but returned by supportedValuesOf`);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/supportedValuesOf/units.js b/js/src/tests/test262/intl402/Intl/supportedValuesOf/units.js
new file mode 100644
index 0000000000..9f1084bdf0
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/supportedValuesOf/units.js
@@ -0,0 +1,50 @@
+// Copyright (C) 2021 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.supportedvaluesof
+description: >
+ The returned "unit" values are sorted, unique, and well-formed.
+info: |
+ Intl.supportedValuesOf ( key )
+
+ 1. Let key be ? ToString(key).
+ ...
+ 7. Else if key is "unit", then
+ a. Let list be ! AvailableUnits( ).
+ ...
+ 9. Return ! CreateArrayFromList( list ).
+
+ AvailableUnits ( )
+ The AvailableUnits abstract operation returns a List, ordered as if an Array
+ of the same values had been sorted using %Array.prototype.sort% using
+ undefined as comparefn, that contains the unique values of simple unit
+ identifiers listed in every row of Table 1, except the header row.
+includes: [compareArray.js, testIntl.js]
+features: [Intl-enumeration, Array.prototype.includes]
+---*/
+
+const units = Intl.supportedValuesOf("unit");
+
+assert(Array.isArray(units), "Returns an Array object.");
+assert.sameValue(Object.getPrototypeOf(units), Array.prototype,
+ "The array prototype is Array.prototype");
+
+const otherUnits = Intl.supportedValuesOf("unit");
+assert.notSameValue(otherUnits, units,
+ "Returns a new array object for each call.");
+
+assert.compareArray(units, otherUnits.sort(),
+ "The array is sorted.");
+
+assert.sameValue(new Set(units).size, units.length,
+ "The array doesn't contain duplicates.");
+
+const simpleSanctioned = allSimpleSanctionedUnits();
+
+for (let unit of units) {
+ assert(simpleSanctioned.includes(unit), `${unit} is a simple, sanctioned unit`);
+ assert(!unit.includes("-per-"), `${unit} isn't a compound unit`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/toStringTag/browser.js b/js/src/tests/test262/intl402/Intl/toStringTag/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/toStringTag/browser.js
diff --git a/js/src/tests/test262/intl402/Intl/toStringTag/shell.js b/js/src/tests/test262/intl402/Intl/toStringTag/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/toStringTag/shell.js
diff --git a/js/src/tests/test262/intl402/Intl/toStringTag/toString.js b/js/src/tests/test262/intl402/Intl/toStringTag/toString.js
new file mode 100644
index 0000000000..fdcd994990
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/toStringTag/toString.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl-toStringTag
+description: >
+ Object.prototype.toString utilizes Intl[@@toStringTag] and doesn't special-case Intl namespace object.
+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 [ @@toStringTag ]
+
+ The initial value of the @@toStringTag property is the String value "Intl".
+features: [Symbol.toStringTag]
+---*/
+
+assert.sameValue(Intl.toString(), "[object Intl]");
+assert.sameValue(Object.prototype.toString.call(Intl), "[object Intl]");
+
+Object.defineProperty(Intl, Symbol.toStringTag, { value: "test262" });
+assert.sameValue(Intl.toString(), "[object test262]");
+assert.sameValue(Object.prototype.toString.call(Intl), "[object test262]");
+
+assert(delete Intl[Symbol.toStringTag]);
+assert.sameValue(Intl.toString(), "[object Object]");
+assert.sameValue(Object.prototype.toString.call(Intl), "[object Object]");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/Intl/toStringTag/toStringTag.js b/js/src/tests/test262/intl402/Intl/toStringTag/toStringTag.js
new file mode 100644
index 0000000000..0b5c250369
--- /dev/null
+++ b/js/src/tests/test262/intl402/Intl/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-toStringTag
+description: >
+ Property descriptor of Intl[@@toStringTag].
+info: |
+ Intl [ @@toStringTag ]
+
+ The initial value of the @@toStringTag property is the String value "Intl".
+
+ This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+features: [Symbol.toStringTag]
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl, Symbol.toStringTag, {
+ value: "Intl",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);