diff options
Diffstat (limited to 'js/src/tests/Intl')
49 files changed, 3023 insertions, 0 deletions
diff --git a/js/src/tests/Intl/Array/shell.js b/js/src/tests/Intl/Array/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/Array/shell.js diff --git a/js/src/tests/Intl/Array/toLocaleString-date.js b/js/src/tests/Intl/Array/toLocaleString-date.js new file mode 100644 index 000000000..7711c6064 --- /dev/null +++ b/js/src/tests/Intl/Array/toLocaleString-date.js @@ -0,0 +1,53 @@ +if (typeof Intl === "object") { + const localeSep = [,,].toLocaleString(); + + const date = new Date(Date.UTC(2012, 11, 12, 3, 0, 0)); + + assertEq([date].toLocaleString("en-us", {timeZone: "UTC"}), "12/12/2012, 3:00:00 AM"); + assertEq([date].toLocaleString(["de", "en"], {timeZone: "UTC"}), "12.12.2012, 03:00:00"); + assertEq([date].toLocaleString("th-th", {timeZone: "UTC"}), "12/12/2555 03:00:00"); + assertEq([date].toLocaleString("th-th-u-nu-thai", {timeZone: "UTC"}), "๑๒/๑๒/๒๕๕๕ ๐๓:๐๐:๐๐"); + + const sampleValues = [ + date, new Date(0), + ]; + const sampleLocales = [ + void 0, + "en", + "th-th-u-nu-thai", + "ja-jp", + "ar-ma-u-ca-islamicc", + ["tlh", "de"], + ]; + const numericFormatOptions = { + timeZone: "UTC", + year: "numeric", month: "numeric", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric", + }; + const longFormatOptions = { + timeZone: "UTC", + year: "numeric", month: "long", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric" + }; + const sampleOptions = [ + {timeZone: "UTC"}, + longFormatOptions, + ]; + + for (let locale of sampleLocales) { + for (let options of sampleOptions) { + let dtfOptions; + if (options === longFormatOptions) { + dtfOptions = longFormatOptions; + } else { + dtfOptions = numericFormatOptions; + } + let dtf = new Intl.DateTimeFormat(locale, dtfOptions); + let expected = sampleValues.map(dtf.format).join(localeSep); + assertEq(sampleValues.toLocaleString(locale, options), expected); + } + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/Array/toLocaleString-number.js b/js/src/tests/Intl/Array/toLocaleString-number.js new file mode 100644 index 000000000..6ca8a1783 --- /dev/null +++ b/js/src/tests/Intl/Array/toLocaleString-number.js @@ -0,0 +1,34 @@ +if (typeof Intl === "object") { + const localeSep = [,,].toLocaleString(); + + assertEq([NaN].toLocaleString("ar"), "ليس رقم"); + assertEq([NaN].toLocaleString(["zh-hant", "ar"]), "非數值"); + assertEq([Infinity].toLocaleString("dz"), "གྲངས་མེད"); + assertEq([-Infinity].toLocaleString(["fr", "en"]), "-∞"); + + const sampleValues = [ + -0, +0, -1, +1, -2, +2, -0.5, +0.5, + ]; + const sampleLocales = [ + void 0, + "en", + "th-th-u-nu-thai", + ["tlh", "de"], + ]; + const sampleOptions = [ + void 0, + {}, + {style: "percent"}, + {style: "currency", currency: "USD", minimumIntegerDigits: 4}, + ]; + for (let locale of sampleLocales) { + for (let options of sampleOptions) { + let nf = new Intl.NumberFormat(locale, options); + let expected = sampleValues.map(nf.format).join(localeSep); + assertEq(sampleValues.toLocaleString(locale, options), expected); + } + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/Array/toLocaleString.js b/js/src/tests/Intl/Array/toLocaleString.js new file mode 100644 index 000000000..f94e531f8 --- /dev/null +++ b/js/src/tests/Intl/Array/toLocaleString.js @@ -0,0 +1,35 @@ +if (typeof Intl === "object") { + const localeSep = [,,].toLocaleString(); + + // Missing arguments are passed as |undefined|. + const objNoArgs = { + toLocaleString() { + assertEq(arguments.length, 2); + assertEq(arguments[0], undefined); + assertEq(arguments[1], undefined); + return "pass"; + } + }; + // - Single element case. + assertEq([objNoArgs].toLocaleString(), "pass"); + // - More than one element. + assertEq([objNoArgs, objNoArgs].toLocaleString(), "pass" + localeSep + "pass"); + + // Ensure "locales" and "options" arguments are passed to the array elements. + const locales = {}, options = {}; + const objWithArgs = { + toLocaleString() { + assertEq(arguments.length, 2); + assertEq(arguments[0], locales); + assertEq(arguments[1], options); + return "pass"; + } + }; + // - Single element case. + assertEq([objWithArgs].toLocaleString(locales, options), "pass"); + // - More than one element. + assertEq([objWithArgs, objWithArgs].toLocaleString(locales, options), "pass" + localeSep + "pass"); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/Collator/browser.js b/js/src/tests/Intl/Collator/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/Collator/browser.js diff --git a/js/src/tests/Intl/Collator/compare.js b/js/src/tests/Intl/Collator/compare.js new file mode 100644 index 000000000..9279b85f7 --- /dev/null +++ b/js/src/tests/Intl/Collator/compare.js @@ -0,0 +1,129 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the compare function with a diverse set of locales and options. + +var input = [ + "Argentina", + "Oerlikon", + "Offenbach", + "Sverige", + "Vaticano", + "Zimbabwe", + "la France", + "¡viva España!", + "Österreich", + "中国", + "日本", + "한국", +]; + +var collator, expected; + +function assertEqualArray(actual, expected, collator) { + var description = JSON.stringify(collator.resolvedOptions()); + assertEq(actual.length, expected.length, "array length, " + description); + for (var i = 0; i < actual.length; i++) { + assertEq(actual[i], expected[i], "element " + i + ", " + description); + } +} + + +// Locale en-US; default options. +collator = new Intl.Collator("en-US"); +expected = [ + "¡viva España!", + "Argentina", + "la France", + "Oerlikon", + "Offenbach", + "Österreich", + "Sverige", + "Vaticano", + "Zimbabwe", + "한국", + "中国", + "日本", +]; +assertEqualArray(input.sort(collator.compare), expected, collator); + +// Locale sv-SE; default options. +// Swedish treats "Ö" as a separate character, which sorts after "Z". +collator = new Intl.Collator("sv-SE"); +expected = [ + "¡viva España!", + "Argentina", + "la France", + "Oerlikon", + "Offenbach", + "Sverige", + "Vaticano", + "Zimbabwe", + "Österreich", + "한국", + "中国", + "日本", +]; +assertEqualArray(input.sort(collator.compare), expected, collator); + +// Locale sv-SE; ignore punctuation. +collator = new Intl.Collator("sv-SE", {ignorePunctuation: true}); +expected = [ + "Argentina", + "la France", + "Oerlikon", + "Offenbach", + "Sverige", + "Vaticano", + "¡viva España!", + "Zimbabwe", + "Österreich", + "한국", + "中国", + "日本", +]; +assertEqualArray(input.sort(collator.compare), expected, collator); + +// Locale de-DE; default options. +// In German standard sorting, umlauted characters are treated as variants +// of their base characters: ä ≅ a, ö ≅ o, ü ≅ u. +collator = new Intl.Collator("de-DE"); +expected = [ + "¡viva España!", + "Argentina", + "la France", + "Oerlikon", + "Offenbach", + "Österreich", + "Sverige", + "Vaticano", + "Zimbabwe", + "한국", + "中国", + "日本", +]; +assertEqualArray(input.sort(collator.compare), expected, collator); + +// Locale de-DE; phonebook sort order. +// In German phonebook sorting, umlauted characters are expanded to two-vowel +// sequences: ä → ae, ö → oe, ü → ue. +collator = new Intl.Collator("de-DE-u-co-phonebk"); +expected = [ + "¡viva España!", + "Argentina", + "la France", + "Oerlikon", + "Österreich", + "Offenbach", + "Sverige", + "Vaticano", + "Zimbabwe", + "한국", + "中国", + "日本", +]; +assertEqualArray(input.sort(collator.compare), expected, collator); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/Intl/Collator/shell.js b/js/src/tests/Intl/Collator/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/Collator/shell.js diff --git a/js/src/tests/Intl/Collator/supportedLocalesOf.js b/js/src/tests/Intl/Collator/supportedLocalesOf.js new file mode 100644 index 000000000..7fbebca09 --- /dev/null +++ b/js/src/tests/Intl/Collator/supportedLocalesOf.js @@ -0,0 +1,355 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")||xulRuntime.shell) +// -- test in browser only that ICU has locale data for all Mozilla languages + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This array contains the locales that ICU supports in +// collation whose languages Mozilla localizes Firefox into. +// Current as of ICU 50.1.2 and Firefox March 2013. +var locales = [ + "af", + "af-NA", + "af-ZA", + "ar", + "ar-001", + "ar-AE", + "ar-BH", + "ar-DJ", + "ar-DZ", + "ar-EG", + "ar-EH", + "ar-ER", + "ar-IL", + "ar-IQ", + "ar-JO", + "ar-KM", + "ar-KW", + "ar-LB", + "ar-LY", + "ar-MA", + "ar-MR", + "ar-OM", + "ar-PS", + "ar-QA", + "ar-SA", + "ar-SD", + "ar-SO", + "ar-SY", + "ar-TD", + "ar-TN", + "ar-YE", + "as", + "as-IN", + "be", + "be-BY", + "bg", + "bg-BG", + "bn", + "bn-BD", + "bn-IN", + "bs", + "bs-Cyrl", + "bs-Cyrl-BA", + "bs-Latn", + "bs-Latn-BA", + "ca", + "ca-AD", + "ca-ES", + "cs", + "cs-CZ", + "cy", + "cy-GB", + "da", + "da-DK", + "de", + "de-AT", + "de-BE", + "de-CH", + "de-DE", + "de-LI", + "de-LU", + "el", + "el-CY", + "el-GR", + "en", + "en-150", + "en-AG", + "en-AS", + "en-AU", + "en-BB", + "en-BE", + "en-BM", + "en-BS", + "en-BW", + "en-BZ", + "en-CA", + "en-CM", + "en-DM", + "en-FJ", + "en-FM", + "en-GB", + "en-GD", + "en-GG", + "en-GH", + "en-GI", + "en-GM", + "en-GU", + "en-HK", + "en-IE", + "en-IM", + "en-IN", + "en-JE", + "en-JM", + "en-KE", + "en-KI", + "en-KN", + "en-KY", + "en-LC", + "en-LR", + "en-LS", + "en-MG", + "en-MH", + "en-MP", + "en-MT", + "en-MU", + "en-MW", + "en-NA", + "en-NG", + "en-NZ", + "en-PG", + "en-PH", + "en-PK", + "en-PR", + "en-PW", + "en-SB", + "en-SC", + "en-SG", + "en-SL", + "en-SS", + "en-TC", + "en-TO", + "en-TT", + "en-TZ", + "en-UG", + "en-UM", + "en-US", + "en-US-POSIX", + "en-VC", + "en-VG", + "en-VI", + "en-VU", + "en-WS", + "en-ZA", + "en-ZM", + "en-ZW", + "eo", + "es", + "es-419", + "es-AR", + "es-BO", + "es-CL", + "es-CO", + "es-CR", + "es-CU", + "es-DO", + "es-EA", + "es-EC", + "es-ES", + "es-GQ", + "es-GT", + "es-HN", + "es-IC", + "es-MX", + "es-NI", + "es-PA", + "es-PE", + "es-PH", + "es-PR", + "es-PY", + "es-SV", + "es-US", + "es-UY", + "es-VE", + "et", + "et-EE", + "fa", + "fa-AF", + "fa-IR", + "fi", + "fi-FI", + "fr", + "fr-BE", + "fr-BF", + "fr-BI", + "fr-BJ", + "fr-BL", + "fr-CA", + "fr-CD", + "fr-CF", + "fr-CG", + "fr-CH", + "fr-CI", + "fr-CM", + "fr-DJ", + "fr-DZ", + "fr-FR", + "fr-GA", + "fr-GN", + "fr-GP", + "fr-GQ", + "fr-HT", + "fr-KM", + "fr-LU", + "fr-MA", + "fr-MC", + "fr-MF", + "fr-MG", + "fr-ML", + "fr-MQ", + "fr-MR", + "fr-MU", + "fr-NC", + "fr-NE", + "fr-PF", + "fr-RE", + "fr-RW", + "fr-SC", + "fr-SN", + "fr-SY", + "fr-TD", + "fr-TG", + "fr-TN", + "fr-VU", + "ga", + "ga-IE", + "gu", + "gu-IN", + "he", + "he-IL", + "hi", + "hi-IN", + "hr", + "hr-BA", + "hr-HR", + "hu", + "hu-HU", + "hy", + "hy-AM", + "id", + "id-ID", + "is", + "is-IS", + "it", + "it-CH", + "it-IT", + "it-SM", + "ja", + "ja-JP", + "kk", + "kk-KZ", + "km", + "km-KH", + "kn", + "kn-IN", + "ko", + "ko-KP", + "ko-KR", + "lt", + "lt-LT", + "lv", + "lv-LV", + "mk", + "mk-MK", + "ml", + "ml-IN", + "mr", + "mr-IN", + "nb", + "nb-NO", + "nl", + "nl-AW", + "nl-BE", + "nl-CW", + "nl-NL", + "nl-SR", + "nl-SX", + "nn", + "nn-NO", + "or", + "or-IN", + "pa", + "pa-Arab", + "pa-Arab-PK", + "pa-Guru", + "pa-Guru-IN", + "pl", + "pl-PL", + "pt", + "pt-AO", + "pt-BR", + "pt-CV", + "pt-GW", + "pt-MO", + "pt-MZ", + "pt-PT", + "pt-ST", + "pt-TL", + "ro", + "ro-MD", + "ro-RO", + "ru", + "ru-BY", + "ru-KG", + "ru-KZ", + "ru-MD", + "ru-RU", + "ru-UA", + "si", + "si-LK", + "sk", + "sk-SK", + "sl", + "sl-SI", + "sq", + "sq-AL", + "sq-MK", + "sr", + "sr-Cyrl", + "sr-Cyrl-BA", + "sr-Cyrl-ME", + "sr-Cyrl-RS", + "sr-Latn", + "sr-Latn-BA", + "sr-Latn-ME", + "sr-Latn-RS", + "sv", + "sv-AX", + "sv-FI", + "sv-SE", + "te", + "te-IN", + "th", + "th-TH", + "tr", + "tr-CY", + "tr-TR", + "uk", + "uk-UA", + "vi", + "vi-VN", + "zh", + "zh-Hans", + "zh-Hans-CN", + "zh-Hans-SG", + "zh-Hant", + "zh-Hant-HK", + "zh-Hant-MO", + "zh-Hant-TW", +]; + + +var count = Intl.Collator.supportedLocalesOf(locales).length; + +reportCompare(locales.length, count, "Number of supported locales in Intl.Collator"); diff --git a/js/src/tests/Intl/Date/browser.js b/js/src/tests/Intl/Date/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/Date/browser.js diff --git a/js/src/tests/Intl/Date/shell.js b/js/src/tests/Intl/Date/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/Date/shell.js diff --git a/js/src/tests/Intl/Date/toLocaleDateString_timeZone.js b/js/src/tests/Intl/Date/toLocaleDateString_timeZone.js new file mode 100644 index 000000000..47b77dbe8 --- /dev/null +++ b/js/src/tests/Intl/Date/toLocaleDateString_timeZone.js @@ -0,0 +1,77 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +const defaultLocale = "en-US"; +const defaultDate = Date.UTC(2012, 12-1, 6, 12, 0, 0); +const defaultOptions = { timeZoneName: "short" }; + +const tests = [ + { + timeZone: "UTC", + result: "12/6/2012, GMT", + }, + { + timeZone: "America/Los_Angeles", + result: "12/6/2012, PST", + }, + { + timeZone: "Europe/Berlin", locale: "de", + options: { timeZoneName: "short" }, + result: "6.12.2012, MEZ", + }, + { + timeZone: "Europe/Paris", locale: "fr", + options: { timeZoneName: "long" }, + result: "06/12/2012 à heure normale d’Europe centrale", + }, + { + timeZone: "Asia/Shanghai", locale: "zh-Hans-CN", + options: { timeZoneName: "long" }, + result: "2012/12/6 中国标准时间", + }, + { + timeZone: { toString: () => "Australia/Melbourne" }, locale: "en-AU", + result: "06/12/2012, AEDT", + }, +]; + +for (let {timeZone, result, locale = defaultLocale, date = defaultDate, options = defaultOptions} of tests) { + let s = new Date(date).toLocaleDateString(locale, Object.assign({timeZone}, options)); + assertEq(s, result); +} + + +// |undefined| or absent "timeZone" option selects the default time zone. +{ + let locale = defaultLocale; + let date = defaultDate; + let options = defaultOptions; + + let absentTz = new Date(date).toLocaleDateString(locale, Object.assign({}, options)); + let undefinedTz = new Date(date).toLocaleDateString(locale, Object.assign({timeZone: undefined}, options)); + assertEq(undefinedTz, absentTz); +} + + +// RangeError is thrown for invalid time zone names. +for (let timeZone of ["", "undefined", "UTC\0", "Vienna", "Africa", "America/NewYork"]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleDateString(undefined, {timeZone}); + }, RangeError); +} + +// RangeError is thrown for these values, because ToString(<value>) +// isn't a valid time zone name. +for (let timeZone of [null, 0, 0.5, true, false, [], {}, function() {}]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleDateString(undefined, {timeZone}); + }, RangeError); +} + +// ToString(<symbol>) throws TypeError. +assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleDateString(undefined, {timeZone: Symbol()}); +}, TypeError); + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/Date/toLocaleString_timeZone.js b/js/src/tests/Intl/Date/toLocaleString_timeZone.js new file mode 100644 index 000000000..63e370034 --- /dev/null +++ b/js/src/tests/Intl/Date/toLocaleString_timeZone.js @@ -0,0 +1,77 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +const defaultLocale = "en-US"; +const defaultDate = Date.UTC(2012, 12-1, 6, 12, 0, 0); +const defaultOptions = {}; + +const tests = [ + { + timeZone: "UTC", + result: "12/6/2012, 12:00:00 PM", + }, + { + timeZone: "America/Los_Angeles", + result: "12/6/2012, 4:00:00 AM", + }, + { + timeZone: "Europe/Berlin", locale: "de", + options: { timeZoneName: "short" }, + result: "6.12.2012, 13:00:00 MEZ", + }, + { + timeZone: "Europe/Paris", locale: "fr", + options: { timeZoneName: "long" }, + result: "06/12/2012 à 13:00:00 heure normale d’Europe centrale", + }, + { + timeZone: "Asia/Shanghai", locale: "zh-Hans-CN", + options: { timeZoneName: "long" }, + result: "2012/12/6 中国标准时间 下午8:00:00", + }, + { + timeZone: { toString: () => "Australia/Melbourne" }, locale: "en-AU", + result: "06/12/2012, 11:00:00 pm", + }, +]; + +for (let {timeZone, result, locale = defaultLocale, date = defaultDate, options = defaultOptions} of tests) { + let s = new Date(date).toLocaleString(locale, Object.assign({timeZone}, options)); + assertEq(s, result); +} + + +// |undefined| or absent "timeZone" option selects the default time zone. +{ + let locale = defaultLocale; + let date = defaultDate; + let options = defaultOptions; + + let absentTz = new Date(date).toLocaleString(locale, Object.assign({}, options)); + let undefinedTz = new Date(date).toLocaleString(locale, Object.assign({timeZone: undefined}, options)); + assertEq(undefinedTz, absentTz); +} + + +// RangeError is thrown for invalid time zone names. +for (let timeZone of ["", "undefined", "UTC\0", "Vienna", "Africa", "America/NewYork"]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleString(undefined, {timeZone}); + }, RangeError); +} + +// RangeError is thrown for these values, because ToString(<value>) +// isn't a valid time zone name. +for (let timeZone of [null, 0, 0.5, true, false, [], {}, function() {}]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleString(undefined, {timeZone}); + }, RangeError); +} + +// ToString(<symbol>) throws TypeError. +assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleString(undefined, {timeZone: Symbol()}); +}, TypeError); + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/Date/toLocaleTimeString_timeZone.js b/js/src/tests/Intl/Date/toLocaleTimeString_timeZone.js new file mode 100644 index 000000000..14799a287 --- /dev/null +++ b/js/src/tests/Intl/Date/toLocaleTimeString_timeZone.js @@ -0,0 +1,77 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +const defaultLocale = "en-US"; +const defaultDate = Date.UTC(2012, 12-1, 6, 12, 0, 0); +const defaultOptions = {}; + +const tests = [ + { + timeZone: "UTC", + result: "12:00:00 PM", + }, + { + timeZone: "America/Los_Angeles", + result: "4:00:00 AM", + }, + { + timeZone: "Europe/Berlin", locale: "de", + options: { timeZoneName: "short" }, + result: "13:00:00 MEZ", + }, + { + timeZone: "Europe/Paris", locale: "fr", + options: { timeZoneName: "long" }, + result: "13:00:00 heure normale d’Europe centrale", + }, + { + timeZone: "Asia/Shanghai", locale: "zh-Hans-CN", + options: { timeZoneName: "long" }, + result: "中国标准时间 下午8:00:00", + }, + { + timeZone: { toString: () => "Australia/Melbourne" }, locale: "en-AU", + result: "11:00:00 pm", + }, +]; + +for (let {timeZone, result, locale = defaultLocale, date = defaultDate, options = defaultOptions} of tests) { + let s = new Date(date).toLocaleTimeString(locale, Object.assign({timeZone}, options)); + assertEq(s, result); +} + + +// |undefined| or absent "timeZone" option selects the default time zone. +{ + let locale = defaultLocale; + let date = defaultDate; + let options = defaultOptions; + + let absentTz = new Date(date).toLocaleTimeString(locale, Object.assign({}, options)); + let undefinedTz = new Date(date).toLocaleTimeString(locale, Object.assign({timeZone: undefined}, options)); + assertEq(undefinedTz, absentTz); +} + + +// RangeError is thrown for invalid time zone names. +for (let timeZone of ["", "undefined", "UTC\0", "Vienna", "Africa", "America/NewYork"]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleTimeString(undefined, {timeZone}); + }, RangeError); +} + +// RangeError is thrown for these values, because ToString(<value>) +// isn't a valid time zone name. +for (let timeZone of [null, 0, 0.5, true, false, [], {}, function() {}]) { + assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleTimeString(undefined, {timeZone}); + }, RangeError); +} + +// ToString(<symbol>) throws TypeError. +assertThrowsInstanceOf(() => { + new Date(defaultDate).toLocaleTimeString(undefined, {timeZone: Symbol()}); +}, TypeError); + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/DateTimeFormat/browser.js b/js/src/tests/Intl/DateTimeFormat/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/browser.js diff --git a/js/src/tests/Intl/DateTimeFormat/format.js b/js/src/tests/Intl/DateTimeFormat/format.js new file mode 100644 index 000000000..936a7dae3 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/format.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the format function with a diverse set of locales and options. +// Always use UTC to avoid dependencies on test environment. + +var format; +var date = Date.UTC(2012, 11, 12, 3, 0, 0); +var longFormatOptions = {timeZone: "UTC", + year: "numeric", month: "long", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric"}; + +// Locale en-US; default options. +format = new Intl.DateTimeFormat("en-us", {timeZone: "UTC"}); +assertEq(format.format(date), "12/12/2012"); + +// Locale th-TH; default options. +// Thailand uses the Buddhist calendar. +format = new Intl.DateTimeFormat("th-th", {timeZone: "UTC"}); +assertEq(format.format(date), "12/12/2555"); + +// Locale th-TH; long format, Thai digits. +format = new Intl.DateTimeFormat("th-th-u-nu-thai", longFormatOptions); +assertEq(format.format(date), "๑๒ ธันวาคม ๒๕๕๕ ๐๓:๐๐:๐๐"); + +// Locale ja-JP; long format. +format = new Intl.DateTimeFormat("ja-jp", longFormatOptions); +assertEq(format.format(date), "2012年12月12日 3:00:00"); + +// Locale ar-MA; long format, Islamic civilian calendar. +format = new Intl.DateTimeFormat("ar-ma-u-ca-islamicc", longFormatOptions); +assertEq(format.format(date), "28 محرم، 1434 03:00:00"); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/Intl/DateTimeFormat/formatToParts.js b/js/src/tests/Intl/DateTimeFormat/formatToParts.js new file mode 100644 index 000000000..95831e67a --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/formatToParts.js @@ -0,0 +1,170 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +// Tests the format function with a diverse set of locales and options. +// Always use UTC to avoid dependencies on test environment. + +/* + * Return true if A is equal to B, where equality on arrays and objects + * means that they have the same set of enumerable properties, the values + * of each property are deep_equal, and their 'length' properties are + * equal. Equality on other types is ==. + */ +function deepEqual(a, b) { + if (typeof a !== typeof b) + return false; + + if (a === null) + return b === null; + + if (typeof a === 'object') { + // For every property of a, does b have that property with an equal value? + var props = {}; + for (var prop in a) { + if (!deepEqual(a[prop], b[prop])) + return false; + props[prop] = true; + } + + // Are all of b's properties present on a? + for (var prop in b) + if (!props[prop]) + return false; + + // length isn't enumerable, but we want to check it, too. + return a.length === b.length; + } + + return Object.is(a, b); +} + +function composeDate(parts) { + return parts.map(({value}) => value) + .reduce((string, part) => string + part); +} + +var format; +var date = Date.UTC(2012, 11, 17, 3, 0, 42); + +// Locale en-US; default options. +format = new Intl.DateTimeFormat("en-us", {timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'month', value: '12' }, + { type: 'literal', value: '/' }, + { type: 'day', value: '17' }, + { type: 'literal', value: '/' }, + { type: 'year', value: '2012' } +]), true); + +// Just date +format = new Intl.DateTimeFormat("en-us", { + year: 'numeric', + month: 'numeric', + day: 'numeric', + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'month', value: '12' }, + { type: 'literal', value: '/' }, + { type: 'day', value: '17' }, + { type: 'literal', value: '/' }, + { type: 'year', value: '2012' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Just time in hour24 +format = new Intl.DateTimeFormat("en-us", { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: false, + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'hour', value: '03' }, + { type: 'literal', value: ':' }, + { type: 'minute', value: '00' }, + { type: 'literal', value: ':' }, + { type: 'second', value: '42' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Just time in hour12 +format = new Intl.DateTimeFormat("en-us", { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: true, + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'hour', value: '3' }, + { type: 'literal', value: ':' }, + { type: 'minute', value: '00' }, + { type: 'literal', value: ':' }, + { type: 'second', value: '42' }, + { type: 'literal', value: ' ' }, + { type: 'dayPeriod', value: 'AM' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Just month. +format = new Intl.DateTimeFormat("en-us", { + month: "narrow", + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'month', value: 'D' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Just weekday. +format = new Intl.DateTimeFormat("en-us", { + weekday: "narrow", + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'weekday', value: 'M' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Year and era. +format = new Intl.DateTimeFormat("en-us", { + year: "numeric", + era: "short", + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'year', value: '2012' }, + { type: 'literal', value: ' ' }, + { type: 'era', value: 'AD' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +// Time and date +format = new Intl.DateTimeFormat("en-us", { + weekday: 'long', + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: true, + timeZone: "UTC"}); +assertEq(deepEqual(format.formatToParts(date), [ + { type: 'weekday', value: 'Monday' }, + { type: 'literal', value: ', ' }, + { type: 'month', value: '12' }, + { type: 'literal', value: '/' }, + { type: 'day', value: '17' }, + { type: 'literal', value: '/' }, + { type: 'year', value: '2012' }, + { type: 'literal', value: ', ' }, + { type: 'hour', value: '3' }, + { type: 'literal', value: ':' }, + { type: 'minute', value: '00' }, + { type: 'literal', value: ':' }, + { type: 'second', value: '42' }, + { type: 'literal', value: ' ' }, + { type: 'dayPeriod', value: 'AM' } +]), true); +assertEq(composeDate(format.formatToParts(date)), format.format(date)); + +if (typeof reportCompare === "function") + reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/Intl/DateTimeFormat/format_timeZone.js b/js/src/tests/Intl/DateTimeFormat/format_timeZone.js new file mode 100644 index 000000000..a4d4dd1c4 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/format_timeZone.js @@ -0,0 +1,104 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +const defaultLocale = "en-US"; +const defaultDate = Date.UTC(2012, 12-1, 6, 12, 0, 0); +const defaultOptions = { + year: "numeric", month: "numeric", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric", +}; +const longFormatOptions = Object.assign({}, defaultOptions, { + month: "long" +}); +const tzNameFormatOptions = Object.assign({}, defaultOptions, { + timeZoneName: "short" +}); + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + +const tests = [ + { + timeZone: "UTC", + result: "12/6/2012, 12:00:00 PM", + }, + { + timeZone: "America/Los_Angeles", + result: "12/6/2012, 4:00:00 AM", + }, + { + timeZone: "America/New_York", + options: tzNameFormatOptions, + result: "12/6/2012, 7:00:00 AM EST", + }, + { + timeZone: "America/Caracas", + result: "12/6/2012, 7:30:00 AM", + }, + { + timeZone: "Europe/London", + result: "12/6/2012, 12:00:00 PM", + }, + { + timeZone: "Africa/Casablanca", + locale: "ar-MA-u-ca-islamicc", options: longFormatOptions, + result: "22 محرم، 1434 12:00:00", + }, + { + timeZone: "Europe/Berlin", + locale: "de-DE", options: tzNameFormatOptions, + result: "6.12.2012, 13:00:00 MEZ", + }, + { + timeZone: "Asia/Kathmandu", + result: "12/6/2012, 5:45:00 PM", + }, + { + timeZone: "Asia/Bangkok", + locale: "th-th-u-nu-thai", options: longFormatOptions, + result: "๖ ธันวาคม ๒๕๕๕ ๑๙:๐๐:๐๐", + }, + { + timeZone: "Asia/Tokyo", + locale: "ja-JP", options: longFormatOptions, + result: "2012年12月6日 21:00:00", + }, + { + timeZone: "Australia/Lord_Howe", + result: "12/6/2012, 11:00:00 PM", + }, + { + timeZone: "Australia/Lord_Howe", + date: Date.UTC(2012, 7-1, 6, 12, 0, 0), + result: "7/6/2012, 10:30:00 PM", + }, + { + timeZone: "Pacific/Kiritimati", + date: Date.UTC(1978, 12-1, 6, 12, 0, 0), + result: "12/6/1978, 1:20:00 AM", + }, + { + timeZone: "Africa/Monrovia", + date: Date.UTC(1971, 12-1, 6, 12, 0, 0), + result: "12/6/1971, 11:15:30 AM", + }, + { + timeZone: "Asia/Riyadh", + date: Date.UTC(1946, 12-1, 6, 12, 0, 0), + result: "12/6/1946, 3:06:52 PM", + }, +]; + +for (let {timeZone, result, locale = defaultLocale, date = defaultDate, options = defaultOptions} of tests) { + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(locale, Object.assign({timeZone: map(timeZone)}, options)); + assertEq(dtf.format(date), result); + assertEq(dtf.resolvedOptions().timeZone, timeZone); + } +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/DateTimeFormat/shell.js b/js/src/tests/Intl/DateTimeFormat/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/shell.js diff --git a/js/src/tests/Intl/DateTimeFormat/supportedLocalesOf.js b/js/src/tests/Intl/DateTimeFormat/supportedLocalesOf.js new file mode 100644 index 000000000..b957f9cd6 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/supportedLocalesOf.js @@ -0,0 +1,371 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")||xulRuntime.shell) +// -- test in browser only that ICU has locale data for all Mozilla languages + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This array contains the locales that ICU supports in +// date and time formatting whose languages Mozilla localizes Firefox into. +// Current as of ICU 50.1.2 and Firefox March 2013. +var locales = [ + "af", + "af-NA", + "af-ZA", + "ar", + "ar-001", + "ar-AE", + "ar-BH", + "ar-DJ", + "ar-DZ", + "ar-EG", + "ar-EH", + "ar-ER", + "ar-IL", + "ar-IQ", + "ar-JO", + "ar-KM", + "ar-KW", + "ar-LB", + "ar-LY", + "ar-MA", + "ar-MR", + "ar-OM", + "ar-PS", + "ar-QA", + "ar-SA", + "ar-SD", + "ar-SO", + "ar-SY", + "ar-TD", + "ar-TN", + "ar-YE", + "as", + "as-IN", + "be", + "be-BY", + "bg", + "bg-BG", + "bn", + "bn-BD", + "bn-IN", + "br", + "br-FR", + "bs", + "bs-Cyrl", + "bs-Cyrl-BA", + "bs-Latn", + "bs-Latn-BA", + "ca", + "ca-AD", + "ca-ES", + "cs", + "cs-CZ", + "cy", + "cy-GB", + "da", + "da-DK", + "de", + "de-AT", + "de-BE", + "de-CH", + "de-DE", + "de-LI", + "de-LU", + "el", + "el-CY", + "el-GR", + "en", + "en-150", + "en-AG", + "en-AS", + "en-AU", + "en-BB", + "en-BE", + "en-BM", + "en-BS", + "en-BW", + "en-BZ", + "en-CA", + "en-CM", + "en-DM", + "en-FJ", + "en-FM", + "en-GB", + "en-GD", + "en-GG", + "en-GH", + "en-GI", + "en-GM", + "en-GU", + "en-GY", + "en-HK", + "en-IE", + "en-IM", + "en-IN", + "en-JE", + "en-JM", + "en-KE", + "en-KI", + "en-KN", + "en-KY", + "en-LC", + "en-LR", + "en-LS", + "en-MG", + "en-MH", + "en-MP", + "en-MT", + "en-MU", + "en-MW", + "en-NA", + "en-NG", + "en-NZ", + "en-PG", + "en-PH", + "en-PK", + "en-PR", + "en-PW", + "en-SB", + "en-SC", + "en-SG", + "en-SL", + "en-SS", + "en-SZ", + "en-TC", + "en-TO", + "en-TT", + "en-TZ", + "en-UG", + "en-UM", + "en-US", + "en-US-POSIX", + "en-VC", + "en-VG", + "en-VI", + "en-VU", + "en-WS", + "en-ZA", + "en-ZM", + "en-ZW", + "eo", + "es", + "es-419", + "es-AR", + "es-BO", + "es-CL", + "es-CO", + "es-CR", + "es-CU", + "es-DO", + "es-EA", + "es-EC", + "es-ES", + "es-GQ", + "es-GT", + "es-HN", + "es-IC", + "es-MX", + "es-NI", + "es-PA", + "es-PE", + "es-PH", + "es-PR", + "es-PY", + "es-SV", + "es-US", + "es-UY", + "es-VE", + "et", + "et-EE", + "eu", + "eu-ES", + "fa", + "fa-AF", + "fa-IR", + "ff", + "ff-SN", + "fi", + "fi-FI", + "fr", + "fr-BE", + "fr-BF", + "fr-BI", + "fr-BJ", + "fr-BL", + "fr-CA", + "fr-CD", + "fr-CF", + "fr-CG", + "fr-CH", + "fr-CI", + "fr-CM", + "fr-DJ", + "fr-DZ", + "fr-FR", + "fr-GA", + "fr-GF", + "fr-GN", + "fr-GP", + "fr-GQ", + "fr-HT", + "fr-KM", + "fr-LU", + "fr-MA", + "fr-MC", + "fr-MF", + "fr-MG", + "fr-ML", + "fr-MQ", + "fr-MR", + "fr-MU", + "fr-NC", + "fr-NE", + "fr-PF", + "fr-RE", + "fr-RW", + "fr-SC", + "fr-SN", + "fr-SY", + "fr-TD", + "fr-TG", + "fr-TN", + "fr-VU", + "fr-YT", + "ga", + "ga-IE", + "gl", + "gl-ES", + "gu", + "gu-IN", + "he", + "he-IL", + "hi", + "hi-IN", + "hr", + "hr-BA", + "hr-HR", + "hu", + "hu-HU", + "hy", + "hy-AM", + "id", + "id-ID", + "is", + "is-IS", + "it", + "it-CH", + "it-IT", + "it-SM", + "ja", + "ja-JP", + "kk", + "kk-Cyrl", + "kk-Cyrl-KZ", + "km", + "km-KH", + "kn", + "kn-IN", + "ko", + "ko-KP", + "ko-KR", + "lt", + "lt-LT", + "lv", + "lv-LV", + "mk", + "mk-MK", + "ml", + "ml-IN", + "mr", + "mr-IN", + "nb", + "nb-NO", + "nl", + "nl-AW", + "nl-BE", + "nl-CW", + "nl-NL", + "nl-SR", + "nl-SX", + "nn", + "nn-NO", + "or", + "or-IN", + "pa", + "pa-Arab", + "pa-Arab-PK", + "pa-Guru", + "pa-Guru-IN", + "pl", + "pl-PL", + "pt", + "pt-AO", + "pt-BR", + "pt-CV", + "pt-GW", + "pt-MO", + "pt-MZ", + "pt-PT", + "pt-ST", + "pt-TL", + "rm", + "rm-CH", + "ro", + "ro-MD", + "ro-RO", + "ru", + "ru-BY", + "ru-KG", + "ru-KZ", + "ru-MD", + "ru-RU", + "ru-UA", + "si", + "si-LK", + "sk", + "sk-SK", + "sl", + "sl-SI", + "sq", + "sq-AL", + "sq-MK", + "sr", + "sr-Cyrl", + "sr-Cyrl-BA", + "sr-Cyrl-ME", + "sr-Cyrl-RS", + "sr-Latn", + "sr-Latn-BA", + "sr-Latn-ME", + "sr-Latn-RS", + "sv", + "sv-AX", + "sv-FI", + "sv-SE", + "te", + "te-IN", + "th", + "th-TH", + "tr", + "tr-CY", + "tr-TR", + "uk", + "uk-UA", + "vi", + "vi-VN", + "zh", + "zh-Hans", + "zh-Hans-CN", + "zh-Hans-HK", + "zh-Hans-MO", + "zh-Hans-SG", + "zh-Hant", + "zh-Hant-HK", + "zh-Hant-MO", + "zh-Hant-TW", +]; + +var count = Intl.DateTimeFormat.supportedLocalesOf(locales).length; + +reportCompare(locales.length, count, "Number of supported locales in Intl.DateTimeFormat"); diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone.js b/js/src/tests/Intl/DateTimeFormat/timeZone.js new file mode 100644 index 000000000..94d0fdc1f --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/timeZone.js @@ -0,0 +1,152 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + + +const utcTimeZones = [ + // Etc/UTC and Etc/GMT are normalized to UTC. + "Etc/UTC", "Etc/GMT", + + // Links to Etc/GMT. (tzdata/etcetera) + "GMT", "Etc/Greenwich", "Etc/GMT-0", "Etc/GMT+0", "Etc/GMT0", + + // Links to Etc/UTC. (tzdata/etcetera) + "Etc/Universal", "Etc/Zulu", + + // Links to Etc/GMT. (tzdata/backward) + "GMT+0", "GMT-0", "GMT0", "Greenwich", + + // Links to Etc/UTC. (tzdata/backward) + "UTC", "Universal", "Zulu", +]; + +for (let timeZone of utcTimeZones) { + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(timeZone)}); + assertEq(dtf.resolvedOptions().timeZone, "UTC"); + } +} + + +// ECMA-402 doesn't normalize Etc/UCT to UTC. +const uctTimeZones = [ + "Etc/UCT", "UCT", +]; + +for (let timeZone of uctTimeZones) { + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(timeZone)}); + assertEq(dtf.resolvedOptions().timeZone, "Etc/UCT"); + } +} + + +const invalidTimeZones = [ + "", "null", "undefined", "UTC\0", + + // ICU time zone name for invalid time zones. + "Etc/Unknown", + + // ICU custom time zones. + "GMT-1", "GMT+1", "GMT-10", "GMT+10", + "GMT-10:00", "GMT+10:00", + "GMT-1000", "GMT+1000", + + // Legacy ICU time zones. + "ACT", "AET", "AGT", "ART", "AST", "BET", "BST", "CAT", "CNT", "CST", + "CTT", "EAT", "ECT", "IET", "IST", "JST", "MIT", "NET", "NST", "PLT", + "PNT", "PRT", "PST", "SST", "VST", + + // Deprecated IANA time zones. + "SystemV/AST4ADT", "SystemV/EST5EDT", "SystemV/CST6CDT", "SystemV/MST7MDT", + "SystemV/PST8PDT", "SystemV/YST9YDT", "SystemV/AST4", "SystemV/EST5", + "SystemV/CST6", "SystemV/MST7", "SystemV/PST8", "SystemV/YST9", "SystemV/HST10", +]; + +for (let timeZone of invalidTimeZones) { + for (let map of tzMapper) { + assertThrowsInstanceOf(() => { + new Intl.DateTimeFormat(undefined, {timeZone: map(timeZone)}); + }, RangeError); + } +} + + +// GMT[+-]hh is invalid, but Etc/GMT[+-]hh is a valid IANA time zone. +for (let gmtOffset = -14; gmtOffset <= 12; ++gmtOffset) { + // Skip Etc/GMT0. + if (gmtOffset === 0) + continue; + + let timeZone = `Etc/GMT${gmtOffset > 0 ? "+" : ""}${gmtOffset}`; + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(timeZone)}); + assertEq(dtf.resolvedOptions().timeZone, timeZone); + } +} + + +const invalidEtcGMTNames = [ + // Out of bounds GMT offset. + "Etc/GMT-15", "Etc/GMT+13", + + // Etc/GMT[+-]hh:mm isn't a IANA time zone name. + "Etc/GMT-10:00", "Etc/GMT+10:00", + "Etc/GMT-1000", "Etc/GMT+1000", +]; + +for (let timeZone of invalidEtcGMTNames) { + for (let map of tzMapper) { + assertThrowsInstanceOf(() => { + new Intl.DateTimeFormat(undefined, {timeZone: map(timeZone)}); + }, RangeError); + } +} + + +// RangeError is thrown for primitive values, because ToString(<primitive>) +// isn't a valid time zone name. +for (let nonStrings of [null, 0, 0.5, true, false]) { + assertThrowsInstanceOf(() => { + new Intl.DateTimeFormat(undefined, {timeZone: nonStrings}); + }, RangeError); +} + +// ToString(<symbol>) throws TypeError. +assertThrowsInstanceOf(() => { + new Intl.DateTimeFormat(undefined, {timeZone: Symbol()}); +}, TypeError); + +// |undefined| or absent "timeZone" option selects the default time zone. +{ + let {timeZone: tzAbsent} = new Intl.DateTimeFormat(undefined, {}).resolvedOptions(); + let {timeZone: tzUndefined} = new Intl.DateTimeFormat(undefined, {timeZone: undefined}).resolvedOptions(); + + assertEq(typeof tzAbsent, "string"); + assertEq(typeof tzUndefined, "string"); + assertEq(tzUndefined, tzAbsent); + + // The default time zone isn't a link name. + let {timeZone: tzDefault} = new Intl.DateTimeFormat(undefined, {timeZone: tzAbsent}).resolvedOptions(); + assertEq(tzDefault, tzAbsent); +} + +// Objects are converted through ToString(). +{ + let timeZone = "Europe/Warsaw"; + let obj = { + toString() { + return timeZone; + } + }; + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: obj}); + assertEq(dtf.resolvedOptions().timeZone, timeZone); +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js new file mode 100644 index 000000000..aeb1fc043 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -0,0 +1,134 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +// Generated by make_intl_data.py. DO NOT EDIT. +// tzdata version = 2017c + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + +// Link names derived from IANA Time Zone Database, backward file. +const links = { + "Africa/Asmera": "Africa/Asmara", + "America/Atka": "America/Adak", + "America/Buenos_Aires": "America/Argentina/Buenos_Aires", + "America/Catamarca": "America/Argentina/Catamarca", + "America/Cordoba": "America/Argentina/Cordoba", + "America/Fort_Wayne": "America/Indiana/Indianapolis", + "America/Indianapolis": "America/Indiana/Indianapolis", + "America/Jujuy": "America/Argentina/Jujuy", + "America/Knox_IN": "America/Indiana/Knox", + "America/Louisville": "America/Kentucky/Louisville", + "America/Mendoza": "America/Argentina/Mendoza", + "America/Porto_Acre": "America/Rio_Branco", + "America/Santa_Isabel": "America/Tijuana", + "America/Shiprock": "America/Denver", + "America/Virgin": "America/Port_of_Spain", + "Antarctica/South_Pole": "Antarctica/McMurdo", + "Asia/Ashkhabad": "Asia/Ashgabat", + "Asia/Calcutta": "Asia/Kolkata", + "Asia/Chungking": "Asia/Chongqing", + "Asia/Dacca": "Asia/Dhaka", + "Asia/Katmandu": "Asia/Kathmandu", + "Asia/Macao": "Asia/Macau", + "Asia/Rangoon": "Asia/Yangon", + "Asia/Saigon": "Asia/Ho_Chi_Minh", + "Asia/Thimbu": "Asia/Thimphu", + "Asia/Ujung_Pandang": "Asia/Makassar", + "Asia/Ulan_Bator": "Asia/Ulaanbaatar", + "Atlantic/Faeroe": "Atlantic/Faroe", + "Australia/ACT": "Australia/Sydney", + "Australia/Canberra": "Australia/Sydney", + "Australia/LHI": "Australia/Lord_Howe", + "Australia/NSW": "Australia/Sydney", + "Australia/North": "Australia/Darwin", + "Australia/Queensland": "Australia/Brisbane", + "Australia/South": "Australia/Adelaide", + "Australia/Tasmania": "Australia/Hobart", + "Australia/Victoria": "Australia/Melbourne", + "Australia/West": "Australia/Perth", + "Australia/Yancowinna": "Australia/Broken_Hill", + "Brazil/Acre": "America/Rio_Branco", + "Brazil/DeNoronha": "America/Noronha", + "Brazil/East": "America/Sao_Paulo", + "Brazil/West": "America/Manaus", + "Canada/Atlantic": "America/Halifax", + "Canada/Central": "America/Winnipeg", + "Canada/Eastern": "America/Toronto", + "Canada/Mountain": "America/Edmonton", + "Canada/Newfoundland": "America/St_Johns", + "Canada/Pacific": "America/Vancouver", + "Canada/Saskatchewan": "America/Regina", + "Canada/Yukon": "America/Whitehorse", + "Chile/Continental": "America/Santiago", + "Chile/EasterIsland": "Pacific/Easter", + "Cuba": "America/Havana", + "Egypt": "Africa/Cairo", + "Eire": "Europe/Dublin", + "GB": "Europe/London", + "GB-Eire": "Europe/London", + "GMT+0": "Etc/GMT", + "GMT-0": "Etc/GMT", + "GMT0": "Etc/GMT", + "Greenwich": "Etc/GMT", + "Hongkong": "Asia/Hong_Kong", + "Iceland": "Atlantic/Reykjavik", + "Iran": "Asia/Tehran", + "Israel": "Asia/Jerusalem", + "Jamaica": "America/Jamaica", + "Japan": "Asia/Tokyo", + "Kwajalein": "Pacific/Kwajalein", + "Libya": "Africa/Tripoli", + "Mexico/BajaNorte": "America/Tijuana", + "Mexico/BajaSur": "America/Mazatlan", + "Mexico/General": "America/Mexico_City", + "NZ": "Pacific/Auckland", + "NZ-CHAT": "Pacific/Chatham", + "Navajo": "America/Denver", + "PRC": "Asia/Shanghai", + "Pacific/Ponape": "Pacific/Pohnpei", + "Pacific/Samoa": "Pacific/Pago_Pago", + "Pacific/Truk": "Pacific/Chuuk", + "Pacific/Yap": "Pacific/Chuuk", + "Poland": "Europe/Warsaw", + "Portugal": "Europe/Lisbon", + "ROC": "Asia/Taipei", + "ROK": "Asia/Seoul", + "Singapore": "Asia/Singapore", + "Turkey": "Europe/Istanbul", + "UCT": "Etc/UCT", + "US/Alaska": "America/Anchorage", + "US/Aleutian": "America/Adak", + "US/Arizona": "America/Phoenix", + "US/Central": "America/Chicago", + "US/East-Indiana": "America/Indiana/Indianapolis", + "US/Eastern": "America/New_York", + "US/Hawaii": "Pacific/Honolulu", + "US/Indiana-Starke": "America/Indiana/Knox", + "US/Michigan": "America/Detroit", + "US/Mountain": "America/Denver", + "US/Pacific": "America/Los_Angeles", + "US/Samoa": "Pacific/Pago_Pago", + "UTC": "Etc/UTC", + "Universal": "Etc/UTC", + "W-SU": "Europe/Moscow", + "Zulu": "Etc/UTC", +}; + +for (let [linkName, target] of Object.entries(links)) { + if (target === "Etc/UTC" || target === "Etc/GMT") + target = "UTC"; + + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)}); + let resolvedTimeZone = dtf.resolvedOptions().timeZone; + assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`); + } +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); + diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js new file mode 100644 index 000000000..b9d957a82 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -0,0 +1,115 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +// Generated by make_intl_data.py. DO NOT EDIT. +// tzdata version = 2017c + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + +// This file was generated with historical, pre-1970 backzone information +// respected. Therefore, every zone key listed below is its own Zone, not +// a Link to a modern-day target as IANA ignoring backzones would say. + +// Backzone zones derived from IANA Time Zone Database. +const links = { + "Africa/Addis_Ababa": "Africa/Addis_Ababa", + "Africa/Asmara": "Africa/Asmara", + "Africa/Bamako": "Africa/Bamako", + "Africa/Bangui": "Africa/Bangui", + "Africa/Banjul": "Africa/Banjul", + "Africa/Blantyre": "Africa/Blantyre", + "Africa/Brazzaville": "Africa/Brazzaville", + "Africa/Bujumbura": "Africa/Bujumbura", + "Africa/Conakry": "Africa/Conakry", + "Africa/Dakar": "Africa/Dakar", + "Africa/Dar_es_Salaam": "Africa/Dar_es_Salaam", + "Africa/Djibouti": "Africa/Djibouti", + "Africa/Douala": "Africa/Douala", + "Africa/Freetown": "Africa/Freetown", + "Africa/Gaborone": "Africa/Gaborone", + "Africa/Harare": "Africa/Harare", + "Africa/Kampala": "Africa/Kampala", + "Africa/Kigali": "Africa/Kigali", + "Africa/Kinshasa": "Africa/Kinshasa", + "Africa/Libreville": "Africa/Libreville", + "Africa/Lome": "Africa/Lome", + "Africa/Luanda": "Africa/Luanda", + "Africa/Lubumbashi": "Africa/Lubumbashi", + "Africa/Lusaka": "Africa/Lusaka", + "Africa/Malabo": "Africa/Malabo", + "Africa/Maseru": "Africa/Maseru", + "Africa/Mbabane": "Africa/Mbabane", + "Africa/Mogadishu": "Africa/Mogadishu", + "Africa/Niamey": "Africa/Niamey", + "Africa/Nouakchott": "Africa/Nouakchott", + "Africa/Ouagadougou": "Africa/Ouagadougou", + "Africa/Porto-Novo": "Africa/Porto-Novo", + "Africa/Sao_Tome": "Africa/Sao_Tome", + "Africa/Timbuktu": "Africa/Timbuktu", + "America/Anguilla": "America/Anguilla", + "America/Antigua": "America/Antigua", + "America/Argentina/ComodRivadavia": "America/Argentina/ComodRivadavia", + "America/Aruba": "America/Aruba", + "America/Cayman": "America/Cayman", + "America/Coral_Harbour": "America/Coral_Harbour", + "America/Dominica": "America/Dominica", + "America/Ensenada": "America/Ensenada", + "America/Grenada": "America/Grenada", + "America/Guadeloupe": "America/Guadeloupe", + "America/Montreal": "America/Montreal", + "America/Montserrat": "America/Montserrat", + "America/Rosario": "America/Rosario", + "America/St_Kitts": "America/St_Kitts", + "America/St_Lucia": "America/St_Lucia", + "America/St_Thomas": "America/St_Thomas", + "America/St_Vincent": "America/St_Vincent", + "America/Tortola": "America/Tortola", + "Antarctica/McMurdo": "Antarctica/McMurdo", + "Asia/Aden": "Asia/Aden", + "Asia/Bahrain": "Asia/Bahrain", + "Asia/Chongqing": "Asia/Chongqing", + "Asia/Harbin": "Asia/Harbin", + "Asia/Kashgar": "Asia/Kashgar", + "Asia/Kuwait": "Asia/Kuwait", + "Asia/Muscat": "Asia/Muscat", + "Asia/Phnom_Penh": "Asia/Phnom_Penh", + "Asia/Tel_Aviv": "Asia/Tel_Aviv", + "Asia/Vientiane": "Asia/Vientiane", + "Atlantic/Jan_Mayen": "Atlantic/Jan_Mayen", + "Atlantic/St_Helena": "Atlantic/St_Helena", + "Europe/Belfast": "Europe/Belfast", + "Europe/Guernsey": "Europe/Guernsey", + "Europe/Isle_of_Man": "Europe/Isle_of_Man", + "Europe/Jersey": "Europe/Jersey", + "Europe/Ljubljana": "Europe/Ljubljana", + "Europe/Sarajevo": "Europe/Sarajevo", + "Europe/Skopje": "Europe/Skopje", + "Europe/Tiraspol": "Europe/Tiraspol", + "Europe/Vaduz": "Europe/Vaduz", + "Europe/Zagreb": "Europe/Zagreb", + "Indian/Antananarivo": "Indian/Antananarivo", + "Indian/Comoro": "Indian/Comoro", + "Indian/Mayotte": "Indian/Mayotte", + "Pacific/Johnston": "Pacific/Johnston", + "Pacific/Midway": "Pacific/Midway", + "Pacific/Saipan": "Pacific/Saipan", +}; + +for (let [linkName, target] of Object.entries(links)) { + if (target === "Etc/UTC" || target === "Etc/GMT") + target = "UTC"; + + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)}); + let resolvedTimeZone = dtf.resolvedOptions().timeZone; + assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`); + } +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); + diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js new file mode 100644 index 000000000..7a358e997 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +// Generated by make_intl_data.py. DO NOT EDIT. +// tzdata version = 2017c + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + +// This file was generated with historical, pre-1970 backzone information +// respected. Therefore, every zone key listed below points to a target +// in the backzone file and not to its modern-day target as IANA ignoring +// backzones would say. + +// Backzone links derived from IANA Time Zone Database. +const links = { + "Africa/Asmera": "Africa/Asmara", + "Antarctica/South_Pole": "Antarctica/McMurdo", + "Asia/Chungking": "Asia/Chongqing", +}; + +for (let [linkName, target] of Object.entries(links)) { + if (target === "Etc/UTC" || target === "Etc/GMT") + target = "UTC"; + + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)}); + let resolvedTimeZone = dtf.resolvedOptions().timeZone; + assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`); + } +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); + diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js new file mode 100644 index 000000000..9515cb394 --- /dev/null +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +// Generated by make_intl_data.py. DO NOT EDIT. +// tzdata version = 2017c + +const tzMapper = [ + x => x, + x => x.toUpperCase(), + x => x.toLowerCase(), +]; + +// Link names derived from IANA Time Zone Database, excluding backward file. +const links = { + "America/Kralendijk": "America/Curacao", + "America/Lower_Princes": "America/Curacao", + "America/Marigot": "America/Port_of_Spain", + "America/St_Barthelemy": "America/Port_of_Spain", + "Arctic/Longyearbyen": "Europe/Oslo", + "Asia/Istanbul": "Europe/Istanbul", + "Etc/GMT+0": "Etc/GMT", + "Etc/GMT-0": "Etc/GMT", + "Etc/GMT0": "Etc/GMT", + "Etc/Greenwich": "Etc/GMT", + "Etc/Universal": "Etc/UTC", + "Etc/Zulu": "Etc/UTC", + "Europe/Bratislava": "Europe/Prague", + "Europe/Busingen": "Europe/Zurich", + "Europe/Mariehamn": "Europe/Helsinki", + "Europe/Nicosia": "Asia/Nicosia", + "Europe/Podgorica": "Europe/Belgrade", + "Europe/San_Marino": "Europe/Rome", + "Europe/Vatican": "Europe/Rome", + "GMT": "Etc/GMT", + "US/Pacific-New": "America/Los_Angeles", +}; + +for (let [linkName, target] of Object.entries(links)) { + if (target === "Etc/UTC" || target === "Etc/GMT") + target = "UTC"; + + for (let map of tzMapper) { + let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)}); + let resolvedTimeZone = dtf.resolvedOptions().timeZone; + assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`); + } +} + + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); + diff --git a/js/src/tests/Intl/NumberFormat/StringBuffer.js b/js/src/tests/Intl/NumberFormat/StringBuffer.js new file mode 100644 index 000000000..ab72e21d4 --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/StringBuffer.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The implementation of the format function uses the C++ StringBuffer class, +// which changes its storage model at 32 characters, and uses it in a way which +// also means that there's no room for null-termination at this limit. +// This test makes sure that none of this affects the output. + +var format = new Intl.NumberFormat("it-IT", {minimumFractionDigits: 1}); + +assertEq(format.format(1123123123123123123123.1), "1.123.123.123.123.120.000.000,0"); +assertEq(format.format(12123123123123123123123.1), "12.123.123.123.123.100.000.000,0"); +assertEq(format.format(123123123123123123123123.1), "123.123.123.123.123.000.000.000,0"); + +reportCompare(0, 0, "ok"); diff --git a/js/src/tests/Intl/NumberFormat/browser.js b/js/src/tests/Intl/NumberFormat/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/browser.js diff --git a/js/src/tests/Intl/NumberFormat/duplicate-singleton-variant.js b/js/src/tests/Intl/NumberFormat/duplicate-singleton-variant.js new file mode 100644 index 000000000..61fdf3b7d --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/duplicate-singleton-variant.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Check for duplicate variants and singletons case-insensitively, but don't +// check in privateuse components. + +function checkInvalidLocale(locale) +{ + try + { + new Intl.NumberFormat(locale); + throw new Error("didn't throw"); + } + catch (e) + { + assertEq(e instanceof RangeError, true, + "expected RangeError for locale '" + locale + "', got " + e); + } +} + +var badLocales = + [ + "en-u-foo-U-foo", + "en-tester-Tester", + "en-tesTER-TESter", + "de-DE-u-kn-true-U-kn-true", + "ar-u-foo-q-bar-u-baz", + "ar-z-moo-u-foo-q-bar-z-eit-u-baz", + ]; + +for (var locale of badLocales) + checkInvalidLocale(locale); + +// Fully-privateuse locales are okay. +for (var locale of badLocales) + new Intl.NumberFormat("x-" + locale).format(5); + +// Locales with trailing privateuse also okay. +for (var locale of badLocales) +{ + new Intl.NumberFormat("en-x-" + locale).format(5); + new Intl.NumberFormat("en-u-foo-x-u-" + locale).format(5); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/NumberFormat/format-as-code-or-name.js b/js/src/tests/Intl/NumberFormat/format-as-code-or-name.js new file mode 100644 index 000000000..ba257ecd7 --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/format-as-code-or-name.js @@ -0,0 +1,75 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1093421; +var summary = + "new Intl.NumberFormat(..., { style: 'currency', currency: '...', " + + "currencyDisplay: 'name' or 'code' }) should have behavior other than " + + "throwing"; + +print(BUGNUMBER + ": " + summary); + +//----------------------------------------------------------------------------- + +// Test that currencyDisplay: "code" behaves correctly and doesn't throw. + +var usdCodeOptions = + { + style: "currency", + currency: "USD", + currencyDisplay: "code", + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }; +var usDollarsCode = new Intl.NumberFormat("en-US", usdCodeOptions); +assertEq(/USD/.test(usDollarsCode.format(25)), true); + +// ISO 4217 currency codes are formed from an ISO 3166-1 alpha-2 country code +// followed by a third letter. ISO 3166 guarantees that no country code +// starting with "X" will ever be assigned. Stepping carefully around a few +// 4217-designated special "currencies", XQQ will never have a representation. +// Thus, yes: this really is specified to work, as unrecognized or unsupported +// codes pass into the string unmodified. +var xqqCodeOptions = + { + style: "currency", + currency: "XQQ", + currencyDisplay: "code", + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }; +var xqqMoneyCode = new Intl.NumberFormat("en-US", xqqCodeOptions); +assertEq(/XQQ/.test(xqqMoneyCode.format(25)), true); + +// Test that currencyDisplay: "name" behaves without throwing. (Unlike the two +// above tests, the results here aren't guaranteed as the name is +// implementation-defined.) +var usdNameOptions = + { + style: "currency", + currency: "USD", + currencyDisplay: "name", + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }; +var usDollarsName = new Intl.NumberFormat("en-US", usdNameOptions); +assertEq(usDollarsName.format(25), "25 US dollars"); + +// But if the implementation doesn't recognize the currency, the provided code +// is used in place of a proper name, unmolested. +var xqqNameOptions = + { + style: "currency", + currency: "XQQ", + currencyDisplay: "name", + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }; +var xqqMoneyName = new Intl.NumberFormat("en-US", xqqNameOptions); +assertEq(/XQQ/.test(xqqMoneyName.format(25)), true); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/NumberFormat/format.js b/js/src/tests/Intl/NumberFormat/format.js new file mode 100644 index 000000000..1f1dba87a --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/format.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the format function with a diverse set of locales and options. + +var format; + +// Locale en-US; default options. +format = new Intl.NumberFormat("en-us"); +assertEq(format.format(0), "0"); +assertEq(format.format(-1), "-1"); +assertEq(format.format(123456789.123456789), "123,456,789.123"); + +// Locale en-US; currency USD. +// The US dollar uses two fractional digits, and negative values are commonly +// parenthesized. +format = new Intl.NumberFormat("en-us", {style: "currency", currency: "USD"}); +assertEq(format.format(0), "$0.00"); +assertEq(format.format(-1), "-$1.00"); +assertEq(format.format(123456789.123456789), "$123,456,789.12"); + +// Locale ja-JP; currency JPY. +// The Japanese yen has no subunit in real life. +format = new Intl.NumberFormat("ja-jp", {style: "currency", currency: "JPY"}); +assertEq(format.format(0), "¥0"); +assertEq(format.format(-1), "-¥1"); +assertEq(format.format(123456789.123456789), "¥123,456,789"); + +// Locale ar-JO; currency JOD. +// The Jordanian Dinar divides into 1000 fils. Jordan uses (real) Arabic digits. +format = new Intl.NumberFormat("ar-jo", {style: "currency", currency: "JOD"}); +assertEq(format.format(0), "٠٫٠٠٠ د.أ."); +assertEq(format.format(-1), "-١٫٠٠٠ د.أ."); +assertEq(format.format(123456789.123456789), "١٢٣٬٤٥٦٬٧٨٩٫١٢٣ د.أ."); + +// Locale th-TH; Thai digits, percent, two significant digits. +format = new Intl.NumberFormat("th-th-u-nu-thai", + {style: "percent", + minimumSignificantDigits: 2, + maximumSignificantDigits: 2}); +assertEq(format.format(0), "๐.๐%"); +assertEq(format.format(-0.01), "-๑.๐%"); +assertEq(format.format(1.10), "๑๑๐%"); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/Intl/NumberFormat/remove-unicode-extensions.js b/js/src/tests/Intl/NumberFormat/remove-unicode-extensions.js new file mode 100644 index 000000000..4d5d249ad --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/remove-unicode-extensions.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Locale processing is supposed to internally remove any Unicode extension +// sequences in the locale. Test that various weird testcases invoking +// algorithmic edge cases don't assert or throw exceptions. + +var weirdCases = + [ + "x-u-foo", + "en-x-u-foo", + "en-a-bar-x-u-foo", + "en-x-u-foo-a-bar", + "en-a-bar-u-baz-x-u-foo", + ]; + +for (var locale of weirdCases) + Intl.NumberFormat(locale).format(5); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/NumberFormat/shell.js b/js/src/tests/Intl/NumberFormat/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/shell.js diff --git a/js/src/tests/Intl/NumberFormat/significantDigitsOfZero.js b/js/src/tests/Intl/NumberFormat/significantDigitsOfZero.js new file mode 100644 index 000000000..f2cd77cda --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/significantDigitsOfZero.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +// -- test that NumberFormat correctly formats 0 with various numbers of significant digits + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var testData = [ + {minimumSignificantDigits: 1, maximumSignificantDigits: 1, expected: "0"}, + {minimumSignificantDigits: 1, maximumSignificantDigits: 2, expected: "0"}, + {minimumSignificantDigits: 1, maximumSignificantDigits: 3, expected: "0"}, + {minimumSignificantDigits: 1, maximumSignificantDigits: 4, expected: "0"}, + {minimumSignificantDigits: 1, maximumSignificantDigits: 5, expected: "0"}, + {minimumSignificantDigits: 2, maximumSignificantDigits: 2, expected: "0.0"}, + {minimumSignificantDigits: 2, maximumSignificantDigits: 3, expected: "0.0"}, + {minimumSignificantDigits: 2, maximumSignificantDigits: 4, expected: "0.0"}, + {minimumSignificantDigits: 2, maximumSignificantDigits: 5, expected: "0.0"}, + {minimumSignificantDigits: 3, maximumSignificantDigits: 3, expected: "0.00"}, + {minimumSignificantDigits: 3, maximumSignificantDigits: 4, expected: "0.00"}, + {minimumSignificantDigits: 3, maximumSignificantDigits: 5, expected: "0.00"}, +]; + +for (var i = 0; i < testData.length; i++) { + var min = testData[i].minimumSignificantDigits; + var max = testData[i].maximumSignificantDigits; + var options = {minimumSignificantDigits: min, maximumSignificantDigits: max}; + var format = new Intl.NumberFormat("en-US", options); + assertEq(format.format(0), testData[i].expected, + "Wrong formatted string for 0 with " + + "minimumSignificantDigits " + min + + ", maximumSignificantDigits " + max + + ": expected \"" + expected + + "\", actual \"" + actual + "\""); +} + +reportCompare(true, true); diff --git a/js/src/tests/Intl/NumberFormat/supportedLocalesOf.js b/js/src/tests/Intl/NumberFormat/supportedLocalesOf.js new file mode 100644 index 000000000..5ba4470a9 --- /dev/null +++ b/js/src/tests/Intl/NumberFormat/supportedLocalesOf.js @@ -0,0 +1,371 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")||xulRuntime.shell) +// -- test in browser only that ICU has locale data for all Mozilla languages + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This array contains the locales that ICU supports in +// number formatting whose languages Mozilla localizes Firefox into. +// Current as of ICU 50.1.2 and Firefox March 2013. +var locales = [ + "af", + "af-NA", + "af-ZA", + "ar", + "ar-001", + "ar-AE", + "ar-BH", + "ar-DJ", + "ar-DZ", + "ar-EG", + "ar-EH", + "ar-ER", + "ar-IL", + "ar-IQ", + "ar-JO", + "ar-KM", + "ar-KW", + "ar-LB", + "ar-LY", + "ar-MA", + "ar-MR", + "ar-OM", + "ar-PS", + "ar-QA", + "ar-SA", + "ar-SD", + "ar-SO", + "ar-SY", + "ar-TD", + "ar-TN", + "ar-YE", + "as", + "as-IN", + "be", + "be-BY", + "bg", + "bg-BG", + "bn", + "bn-BD", + "bn-IN", + "br", + "br-FR", + "bs", + "bs-Cyrl", + "bs-Cyrl-BA", + "bs-Latn", + "bs-Latn-BA", + "ca", + "ca-AD", + "ca-ES", + "cs", + "cs-CZ", + "cy", + "cy-GB", + "da", + "da-DK", + "de", + "de-AT", + "de-BE", + "de-CH", + "de-DE", + "de-LI", + "de-LU", + "el", + "el-CY", + "el-GR", + "en", + "en-150", + "en-AG", + "en-AS", + "en-AU", + "en-BB", + "en-BE", + "en-BM", + "en-BS", + "en-BW", + "en-BZ", + "en-CA", + "en-CM", + "en-DM", + "en-FJ", + "en-FM", + "en-GB", + "en-GD", + "en-GG", + "en-GH", + "en-GI", + "en-GM", + "en-GU", + "en-GY", + "en-HK", + "en-IE", + "en-IM", + "en-IN", + "en-JE", + "en-JM", + "en-KE", + "en-KI", + "en-KN", + "en-KY", + "en-LC", + "en-LR", + "en-LS", + "en-MG", + "en-MH", + "en-MP", + "en-MT", + "en-MU", + "en-MW", + "en-NA", + "en-NG", + "en-NZ", + "en-PG", + "en-PH", + "en-PK", + "en-PR", + "en-PW", + "en-SB", + "en-SC", + "en-SG", + "en-SL", + "en-SS", + "en-SZ", + "en-TC", + "en-TO", + "en-TT", + "en-TZ", + "en-UG", + "en-UM", + "en-US", + "en-US-POSIX", + "en-VC", + "en-VG", + "en-VI", + "en-VU", + "en-WS", + "en-ZA", + "en-ZM", + "en-ZW", + "eo", + "es", + "es-419", + "es-AR", + "es-BO", + "es-CL", + "es-CO", + "es-CR", + "es-CU", + "es-DO", + "es-EA", + "es-EC", + "es-ES", + "es-GQ", + "es-GT", + "es-HN", + "es-IC", + "es-MX", + "es-NI", + "es-PA", + "es-PE", + "es-PH", + "es-PR", + "es-PY", + "es-SV", + "es-US", + "es-UY", + "es-VE", + "et", + "et-EE", + "eu", + "eu-ES", + "fa", + "fa-AF", + "fa-IR", + "ff", + "ff-SN", + "fi", + "fi-FI", + "fr", + "fr-BE", + "fr-BF", + "fr-BI", + "fr-BJ", + "fr-BL", + "fr-CA", + "fr-CD", + "fr-CF", + "fr-CG", + "fr-CH", + "fr-CI", + "fr-CM", + "fr-DJ", + "fr-DZ", + "fr-FR", + "fr-GA", + "fr-GF", + "fr-GN", + "fr-GP", + "fr-GQ", + "fr-HT", + "fr-KM", + "fr-LU", + "fr-MA", + "fr-MC", + "fr-MF", + "fr-MG", + "fr-ML", + "fr-MQ", + "fr-MR", + "fr-MU", + "fr-NC", + "fr-NE", + "fr-PF", + "fr-RE", + "fr-RW", + "fr-SC", + "fr-SN", + "fr-SY", + "fr-TD", + "fr-TG", + "fr-TN", + "fr-VU", + "fr-YT", + "ga", + "ga-IE", + "gl", + "gl-ES", + "gu", + "gu-IN", + "he", + "he-IL", + "hi", + "hi-IN", + "hr", + "hr-BA", + "hr-HR", + "hu", + "hu-HU", + "hy", + "hy-AM", + "id", + "id-ID", + "is", + "is-IS", + "it", + "it-CH", + "it-IT", + "it-SM", + "ja", + "ja-JP", + "kk", + "kk-Cyrl", + "kk-Cyrl-KZ", + "km", + "km-KH", + "kn", + "kn-IN", + "ko", + "ko-KP", + "ko-KR", + "lt", + "lt-LT", + "lv", + "lv-LV", + "mk", + "mk-MK", + "ml", + "ml-IN", + "mr", + "mr-IN", + "nb", + "nb-NO", + "nl", + "nl-AW", + "nl-BE", + "nl-CW", + "nl-NL", + "nl-SR", + "nl-SX", + "nn", + "nn-NO", + "or", + "or-IN", + "pa", + "pa-Arab", + "pa-Arab-PK", + "pa-Guru", + "pa-Guru-IN", + "pl", + "pl-PL", + "pt", + "pt-AO", + "pt-BR", + "pt-CV", + "pt-GW", + "pt-MO", + "pt-MZ", + "pt-PT", + "pt-ST", + "pt-TL", + "rm", + "rm-CH", + "ro", + "ro-MD", + "ro-RO", + "ru", + "ru-BY", + "ru-KG", + "ru-KZ", + "ru-MD", + "ru-RU", + "ru-UA", + "si", + "si-LK", + "sk", + "sk-SK", + "sl", + "sl-SI", + "sq", + "sq-AL", + "sq-MK", + "sr", + "sr-Cyrl", + "sr-Cyrl-BA", + "sr-Cyrl-ME", + "sr-Cyrl-RS", + "sr-Latn", + "sr-Latn-BA", + "sr-Latn-ME", + "sr-Latn-RS", + "sv", + "sv-AX", + "sv-FI", + "sv-SE", + "te", + "te-IN", + "th", + "th-TH", + "tr", + "tr-CY", + "tr-TR", + "uk", + "uk-UA", + "vi", + "vi-VN", + "zh", + "zh-Hans", + "zh-Hans-CN", + "zh-Hans-HK", + "zh-Hans-MO", + "zh-Hans-SG", + "zh-Hant", + "zh-Hant-HK", + "zh-Hant-MO", + "zh-Hant-TW", +]; + +var count = Intl.NumberFormat.supportedLocalesOf(locales).length; + +reportCompare(locales.length, count, "Number of supported locales in Intl.NumberFormat"); diff --git a/js/src/tests/Intl/README.txt b/js/src/tests/Intl/README.txt new file mode 100644 index 000000000..797b49ab5 --- /dev/null +++ b/js/src/tests/Intl/README.txt @@ -0,0 +1,27 @@ +Integration Tests for ECMAScript Internationalization API +========================================================= + +The tests in this directory test the integration of the ICU library +(Internationalization Components for Unicode) into the implementation of the +ECMAScript Internationalization API in SpiderMonkey. + +These integration tests are complementary to: + +- The Test402 test suite maintained by Ecma TC39, which tests conformance of + an implementation to standard ECMA-402, ECMAScript Internationalization API + Specification. Test402 is currently maintained as part of Test262, the overall + conformance test suite for ECMAScript; for more information, see + http://wiki.ecmascript.org/doku.php?id=test262:test262 + +- The test suite of the ICU library, which tests the implementation of ICU + itself and correct interpretation of the locale data it obtains from CLDR + (Common Locale Data Repository). For information on ICU, see + http://site.icu-project.org + +The integration tests check for a variety of locales and options whether the +results are localized in a way that indicates correct integration with ICU. +Such tests are somewhat fragile because the underlying locale data reflects +real world usage and is therefore subject to change. When the ICU library used +by Mozilla is upgraded, it is likely that some of the integration tests will +fail because of locale data changes; however, others might fail because of +actual software bugs. Failures therefore have to be examined carefully. diff --git a/js/src/tests/Intl/TypedArray/shell.js b/js/src/tests/Intl/TypedArray/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/TypedArray/shell.js diff --git a/js/src/tests/Intl/TypedArray/toLocaleString.js b/js/src/tests/Intl/TypedArray/toLocaleString.js new file mode 100644 index 000000000..7a5d0be30 --- /dev/null +++ b/js/src/tests/Intl/TypedArray/toLocaleString.js @@ -0,0 +1,103 @@ +if (typeof Intl === "object") { + const constructors = [ + Int8Array, + Uint8Array, + Uint8ClampedArray, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + ]; + + const localeSep = [,,].toLocaleString(); + + const originalNumberToLocaleString = Number.prototype.toLocaleString; + + // Missing arguments are passed as |undefined|. + for (let constructor of constructors) { + Number.prototype.toLocaleString = function() { + assertEq(arguments.length, 2); + assertEq(arguments[0], undefined); + assertEq(arguments[1], undefined); + return "pass"; + }; + + // Single element case. + assertEq(new constructor(1).toLocaleString(), "pass"); + + // More than one element. + assertEq(new constructor(2).toLocaleString(), "pass" + localeSep + "pass"); + } + Number.prototype.toLocaleString = originalNumberToLocaleString; + + // Missing options is passed as |undefined|. + for (let constructor of constructors) { + Number.prototype.toLocaleString = function() { + assertEq(arguments.length, 2); + assertEq(arguments[0], locales); + assertEq(arguments[1], undefined); + return "pass"; + }; + let locales = {}; + + // Single element case. + assertEq(new constructor(1).toLocaleString(locales), "pass"); + + // More than one element. + assertEq(new constructor(2).toLocaleString(locales), "pass" + localeSep + "pass"); + } + Number.prototype.toLocaleString = originalNumberToLocaleString; + + // Ensure "locales" and "options" arguments are passed to the array elements. + for (let constructor of constructors) { + Number.prototype.toLocaleString = function() { + assertEq(arguments.length, 2); + assertEq(arguments[0], locales); + assertEq(arguments[1], options); + return "pass"; + }; + let locales = {}; + let options = {}; + + // Single element case. + assertEq(new constructor(1).toLocaleString(locales, options), "pass"); + + // More than one element. + assertEq(new constructor(2).toLocaleString(locales, options), "pass" + localeSep + "pass"); + } + Number.prototype.toLocaleString = originalNumberToLocaleString; + + assertEq(new Float32Array([NaN]).toLocaleString("ar"), "ليس رقم"); + assertEq(new Float64Array([NaN]).toLocaleString(["zh-hant", "ar"]), "非數值"); + assertEq(new Float32Array([Infinity]).toLocaleString(["dz"]), "གྲངས་མེད"); + assertEq(new Float64Array([-Infinity]).toLocaleString(["fr", "en"]), "-∞"); + + const sampleValues = [-0, +0, -1, +1, -2, +2, -0.5, +0.5]; + const sampleLocales = [ + void 0, + "en", + "th-th-u-nu-thai", + ["tlh", "de"], + ]; + const sampleOptions = [ + void 0, + {}, + {style: "percent"}, + {style: "currency", currency: "USD", minimumIntegerDigits: 4}, + ]; + for (let locale of sampleLocales) { + for (let options of sampleOptions) { + let nf = new Intl.NumberFormat(locale, options); + for (let constructor of constructors) { + let typedArray = new constructor(sampleValues); + let expected = [].map.call(typedArray, nf.format).join(localeSep); + assertEq(typedArray.toLocaleString(locale, options), expected); + } + } + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/Intl/browser.js b/js/src/tests/Intl/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/browser.js diff --git a/js/src/tests/Intl/extensions/browser.js b/js/src/tests/Intl/extensions/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/extensions/browser.js diff --git a/js/src/tests/Intl/extensions/options-value-emulates-undefined.js b/js/src/tests/Intl/extensions/options-value-emulates-undefined.js new file mode 100644 index 000000000..a154e0c37 --- /dev/null +++ b/js/src/tests/Intl/extensions/options-value-emulates-undefined.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!xulRuntime.shell) +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 843004; +var summary = + "Use of an object that emulates |undefined| as the sole option must " + + "preclude imputing default values"; + +print(BUGNUMBER + ": " + summary); + +if (typeof Intl !== 'object' && typeof quit == 'function') { + print("Test skipped"); + reportCompare(true, true); + quit(0); +} + +/************** + * BEGIN TEST * + **************/ + +var opt = objectEmulatingUndefined(); +opt.toString = function() { return "long"; }; + +var str = new Date(2013, 12 - 1, 14).toLocaleString("en-US", { weekday: opt }); + +// Because "weekday" was present and not undefined (stringifying to "long"), +// this must be a string like "Saturday" (in this implementation, that is). +assertEq(str, "Saturday"); + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/Intl/extensions/shell.js b/js/src/tests/Intl/extensions/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/extensions/shell.js diff --git a/js/src/tests/Intl/four-letter-language-codes.js b/js/src/tests/Intl/four-letter-language-codes.js new file mode 100644 index 000000000..b92b4c3e1 --- /dev/null +++ b/js/src/tests/Intl/four-letter-language-codes.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// So many non-existent four letter language codes to pick from. +const languageTags = { + "Flob": "flob", + "ZORK": "zork", + "Blah-latn": "blah-Latn", + "QuuX-latn-us": "quux-Latn-US", + "SPAM-gb-x-Sausages-BACON-eggs": "spam-GB-x-sausages-bacon-eggs", +}; + +for (let [tag, canonical] of Object.entries(languageTags)) { + assertEq(Intl.getCanonicalLocales(tag)[0], canonical); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCalendarInfo.js b/js/src/tests/Intl/getCalendarInfo.js new file mode 100644 index 000000000..951fd820e --- /dev/null +++ b/js/src/tests/Intl/getCalendarInfo.js @@ -0,0 +1,83 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCalendarInfo function with a diverse set of arguments. + +function checkCalendarInfo(info, expected) +{ + assertEq(Object.getPrototypeOf(info), Object.prototype); + + assertEq(info.firstDayOfWeek, expected.firstDayOfWeek); + assertEq(info.minDays, expected.minDays); + assertEq(info.weekendStart, expected.weekendStart); + assertEq(info.weekendEnd, expected.weekendEnd); + assertEq(info.calendar, expected.calendar); + assertEq(info.locale, expected.locale); +} + +addIntlExtras(Intl); + +let gCI = Intl.getCalendarInfo; + +assertEq(gCI.length, 1); + +checkCalendarInfo(gCI('en-US'), { + firstDayOfWeek: 1, + minDays: 1, + weekendStart: 7, + weekendEnd: 1, + calendar: "gregory", + locale: "en-US" +}); + +checkCalendarInfo(gCI('en-IL'), { + firstDayOfWeek: 1, + minDays: 1, + weekendStart: 6, + weekendEnd: 7, + calendar: "gregory", + locale: "en-IL" +}); + + +checkCalendarInfo(gCI('en-GB'), { + firstDayOfWeek: 2, + minDays: 4, + weekendStart: 7, + weekendEnd: 1, + calendar: "gregory", + locale: "en-GB" +}); + + +checkCalendarInfo(gCI('pl'), { + firstDayOfWeek: 2, + minDays: 4, + weekendStart: 7, + weekendEnd: 1, + calendar: "gregory", + locale: "pl" +}); + +checkCalendarInfo(gCI('ar-IQ'), { + firstDayOfWeek: 7, + minDays: 1, + weekendStart: 6, + weekendEnd: 7, + calendar: "gregory", + locale: "ar-IQ" +}); + +checkCalendarInfo(gCI('fa-IR'), { + firstDayOfWeek: 7, + minDays: 1, + weekendStart: 6, + weekendEnd: 6, + calendar: "persian", + locale: "fa-IR" +}); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-arg-length.js b/js/src/tests/Intl/getCanonicalLocales-overridden-arg-length.js new file mode 100644 index 000000000..f0cb3d4ee --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales-overridden-arg-length.js @@ -0,0 +1,20 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCanonicalLocales function for overridden argument's length. + +var count = 0; +var locs = { get length() { if (count++ > 0) throw 42; return 0; } }; +var locales = Intl.getCanonicalLocales(locs); // shouldn't throw 42 +assertEq(locales.length, 0); + + +var obj = { get 0() { throw new Error("must not be gotten!"); }, + length: -Math.pow(2, 32) + 1 }; + +assertEq(Intl.getCanonicalLocales(obj).length, 0); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-push.js b/js/src/tests/Intl/getCanonicalLocales-overridden-push.js new file mode 100644 index 000000000..36f53ebf0 --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales-overridden-push.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCanonicalLocales function for overriden Array.push. + +Array.prototype.push = () => { throw 42; }; + +// must not throw 42, might if push is used +var arr = Intl.getCanonicalLocales(["en-US"]); + +assertEqArray(arr, ["en-US"]); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-set.js b/js/src/tests/Intl/getCanonicalLocales-overridden-set.js new file mode 100644 index 000000000..396f3a948 --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales-overridden-set.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCanonicalLocales function for overridden set(). + +Object.defineProperty(Array.prototype, 0, { set() { throw 42; } }); + +// must not throw 42, might if push is used +var arr = Intl.getCanonicalLocales(["en-US"]); + +assertEqArray(arr, ["en-US"]); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-weird-cases.js b/js/src/tests/Intl/getCanonicalLocales-weird-cases.js new file mode 100644 index 000000000..b933eb030 --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales-weird-cases.js @@ -0,0 +1,24 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Locale processing is supposed to internally remove any Unicode extension +// sequences in the locale. Test that various weird testcases invoking +// algorithmic edge cases don't assert or throw exceptions. + +var weirdCases = + [ + "x-u-foo", + "en-x-u-foo", + "en-a-bar-x-u-foo", + "en-x-u-foo-a-bar", + "en-a-bar-u-baz-x-u-foo", + ]; + +for (let weird of weirdCases) + assertEqArray(Intl.getCanonicalLocales(weird), [weird]); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); + diff --git a/js/src/tests/Intl/getCanonicalLocales-with-duplicates.js b/js/src/tests/Intl/getCanonicalLocales-with-duplicates.js new file mode 100644 index 000000000..c02956948 --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales-with-duplicates.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCanonicalLocales function for duplicate locales scenario. + +assertEqArray(Intl.getCanonicalLocales(['ab-cd', 'ff', 'de-rt', 'ab-Cd']), + ['ab-CD', 'ff', 'de-RT']); + +var locales = Intl.getCanonicalLocales(["en-US", "en-US"]); +assertEqArray(locales, ['en-US']); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales.js b/js/src/tests/Intl/getCanonicalLocales.js new file mode 100644 index 000000000..153188160 --- /dev/null +++ b/js/src/tests/Intl/getCanonicalLocales.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCanonicalLocales function with a diverse set of arguments. + +let gCL = Intl.getCanonicalLocales; + +assertEq(Intl.getCanonicalLocales.length, 1); + +assertEqArray(gCL(), []); + +assertEqArray(gCL('ab-cd'), ['ab-CD']); + +assertEqArray(gCL(['ab-cd']), ['ab-CD']); + +assertEqArray(gCL(['ab-cd', 'FF']), ['ab-CD', 'ff']); + +assertEqArray(gCL({'a': 0}), []); + +assertEqArray(gCL({}), []); + +assertEqArray(gCL(['ar-ma-u-ca-islamicc']), ['ar-MA-u-ca-islamicc']); + +assertEqArray(gCL(['th-th-u-nu-thai']), ['th-TH-u-nu-thai']); + +assertEqArray(gCL(NaN), []); + +assertEqArray(gCL(1), []); + +Number.prototype[0] = "en-US"; +Number.prototype.length = 1; +assertEqArray(gCL(NaN), ["en-US"]); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/Intl/shell.js b/js/src/tests/Intl/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/Intl/shell.js |