1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/tests/test262/intl402/browser.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1315 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Undo at least the damage done by taintArray so that the jstests 1.10 + * harness won't die. The properties added to Object.prototype by the various 1.11 + * tests have names that are less likely to cause trouble. 1.12 + */ 1.13 +setRestoreFunction((function () { 1.14 + var Array_indexOf = Array.prototype.indexOf; 1.15 + var Array_join = Array.prototype.join; 1.16 + var Array_push = Array.prototype.push; 1.17 + var Array_slice = Array.prototype.slice; 1.18 + var Array_sort = Array.prototype.sort; 1.19 + return function () { 1.20 + delete Array.prototype["0"]; 1.21 + Array.prototype.indexOf = Array_indexOf; 1.22 + Array.prototype.join = Array_join; 1.23 + Array.prototype.push = Array_push; 1.24 + Array.prototype.slice = Array_slice; 1.25 + Array.prototype.sort = Array_sort; 1.26 + }; 1.27 +}())); 1.28 +// Copyright 2012 Mozilla Corporation. All rights reserved. 1.29 +// This code is governed by the BSD license found in the LICENSE file. 1.30 + 1.31 +/** 1.32 + * @description Tests that obj meets the requirements for built-in objects 1.33 + * defined by the introduction of chapter 15 of the ECMAScript Language Specification. 1.34 + * @param {Object} obj the object to be tested. 1.35 + * @param {boolean} isFunction whether the specification describes obj as a function. 1.36 + * @param {boolean} isConstructor whether the specification describes obj as a constructor. 1.37 + * @param {String[]} properties an array with the names of the built-in properties of obj, 1.38 + * excluding length, prototype, or properties with non-default attributes. 1.39 + * @param {number} length for functions only: the length specified for the function 1.40 + * or derived from the argument list. 1.41 + * @author Norbert Lindenberg 1.42 + */ 1.43 + 1.44 +function testBuiltInObject(obj, isFunction, isConstructor, properties, length) { 1.45 + 1.46 + if (obj === undefined) { 1.47 + $ERROR("Object being tested is undefined."); 1.48 + } 1.49 + 1.50 + var objString = Object.prototype.toString.call(obj); 1.51 + if (isFunction) { 1.52 + if (objString !== "[object Function]") { 1.53 + $ERROR("The [[Class]] internal property of a built-in function must be " + 1.54 + "\"Function\", but toString() returns " + objString); 1.55 + } 1.56 + } else { 1.57 + if (objString !== "[object Object]") { 1.58 + $ERROR("The [[Class]] internal property of a built-in non-function object must be " + 1.59 + "\"Object\", but toString() returns " + objString); 1.60 + } 1.61 + } 1.62 + 1.63 + if (!Object.isExtensible(obj)) { 1.64 + $ERROR("Built-in objects must be extensible."); 1.65 + } 1.66 + 1.67 + if (isFunction && Object.getPrototypeOf(obj) !== Function.prototype) { 1.68 + $ERROR("Built-in functions must have Function.prototype as their prototype."); 1.69 + } 1.70 + 1.71 + if (isConstructor && Object.getPrototypeOf(obj.prototype) !== Object.prototype) { 1.72 + $ERROR("Built-in prototype objects must have Object.prototype as their prototype."); 1.73 + } 1.74 + 1.75 + // verification of the absence of the [[Construct]] internal property has 1.76 + // been moved to the end of the test 1.77 + 1.78 + // verification of the absence of the prototype property has 1.79 + // been moved to the end of the test 1.80 + 1.81 + if (isFunction) { 1.82 + 1.83 + if (typeof obj.length !== "number" || obj.length !== Math.floor(obj.length)) { 1.84 + $ERROR("Built-in functions must have a length property with an integer value."); 1.85 + } 1.86 + 1.87 + if (obj.length !== length) { 1.88 + $ERROR("Function's length property doesn't have specified value; expected " + 1.89 + length + ", got " + obj.length + "."); 1.90 + } 1.91 + 1.92 + var desc = Object.getOwnPropertyDescriptor(obj, "length"); 1.93 + if (desc.writable) { 1.94 + $ERROR("The length property of a built-in function must not be writable."); 1.95 + } 1.96 + if (desc.enumerable) { 1.97 + $ERROR("The length property of a built-in function must not be enumerable."); 1.98 + } 1.99 + if (desc.configurable) { 1.100 + $ERROR("The length property of a built-in function must not be configurable."); 1.101 + } 1.102 + } 1.103 + 1.104 + properties.forEach(function(prop) { 1.105 + var desc = Object.getOwnPropertyDescriptor(obj, prop); 1.106 + if (desc === undefined) { 1.107 + $ERROR("Missing property " + prop + "."); 1.108 + } 1.109 + // accessor properties don't have writable attribute 1.110 + if (desc.hasOwnProperty("writable") && !desc.writable) { 1.111 + $ERROR("The " + prop + " property of this built-in function must be writable."); 1.112 + } 1.113 + if (desc.enumerable) { 1.114 + $ERROR("The " + prop + " property of this built-in function must not be enumerable."); 1.115 + } 1.116 + if (!desc.configurable) { 1.117 + $ERROR("The " + prop + " property of this built-in function must be configurable."); 1.118 + } 1.119 + }); 1.120 + 1.121 + // The remaining sections have been moved to the end of the test because 1.122 + // unbound non-constructor functions written in JavaScript cannot possibly 1.123 + // pass them, and we still want to test JavaScript implementations as much 1.124 + // as possible. 1.125 + 1.126 + var exception; 1.127 + if (isFunction && !isConstructor) { 1.128 + // this is not a complete test for the presence of [[Construct]]: 1.129 + // if it's absent, the exception must be thrown, but it may also 1.130 + // be thrown if it's present and just has preconditions related to 1.131 + // arguments or the this value that this statement doesn't meet. 1.132 + try { 1.133 + /*jshint newcap:false*/ 1.134 + var instance = new obj(); 1.135 + } catch (e) { 1.136 + exception = e; 1.137 + } 1.138 + if (exception === undefined || exception.name !== "TypeError") { 1.139 + $ERROR("Built-in functions that aren't constructors must throw TypeError when " + 1.140 + "used in a \"new\" statement."); 1.141 + } 1.142 + } 1.143 + 1.144 + if (isFunction && !isConstructor && obj.hasOwnProperty("prototype")) { 1.145 + $ERROR("Built-in functions that aren't constructors must not have a prototype property."); 1.146 + } 1.147 + 1.148 + // passed the complete test! 1.149 + return true; 1.150 +} 1.151 + 1.152 +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. 1.153 +// Copyright 2012-2013 Mozilla Corporation. All rights reserved. 1.154 +// This code is governed by the BSD license found in the LICENSE file. 1.155 + 1.156 +/** 1.157 + * This file contains shared functions for the tests in the conformance test 1.158 + * suite for the ECMAScript Internationalization API. 1.159 + * @author Norbert Lindenberg 1.160 + */ 1.161 + 1.162 + 1.163 +/** 1.164 + * @description Calls the provided function for every service constructor in 1.165 + * the Intl object, until f returns a falsy value. It returns the result of the 1.166 + * last call to f, mapped to a boolean. 1.167 + * @param {Function} f the function to call for each service constructor in 1.168 + * the Intl object. 1.169 + * @param {Function} Constructor the constructor object to test with. 1.170 + * @result {Boolean} whether the test succeeded. 1.171 + */ 1.172 +function testWithIntlConstructors(f) { 1.173 + var constructors = ["Collator", "NumberFormat", "DateTimeFormat"]; 1.174 + return constructors.every(function (constructor) { 1.175 + var Constructor = Intl[constructor]; 1.176 + var result; 1.177 + try { 1.178 + result = f(Constructor); 1.179 + } catch (e) { 1.180 + e.message += " (Testing with " + constructor + ".)"; 1.181 + throw e; 1.182 + } 1.183 + return result; 1.184 + }); 1.185 +} 1.186 + 1.187 + 1.188 +/** 1.189 + * Returns the name of the given constructor object, which must be one of 1.190 + * Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat. 1.191 + * @param {object} Constructor a constructor 1.192 + * @return {string} the name of the constructor 1.193 + */ 1.194 +function getConstructorName(Constructor) { 1.195 + switch (Constructor) { 1.196 + case Intl.Collator: 1.197 + return "Collator"; 1.198 + case Intl.NumberFormat: 1.199 + return "NumberFormat"; 1.200 + case Intl.DateTimeFormat: 1.201 + return "DateTimeFormat"; 1.202 + default: 1.203 + $ERROR("test internal error: unknown Constructor"); 1.204 + } 1.205 +} 1.206 + 1.207 + 1.208 +/** 1.209 + * Taints a named data property of the given object by installing 1.210 + * a setter that throws an exception. 1.211 + * @param {object} obj the object whose data property to taint 1.212 + * @param {string} property the property to taint 1.213 + */ 1.214 +function taintDataProperty(obj, property) { 1.215 + Object.defineProperty(obj, property, { 1.216 + set: function(value) { 1.217 + $ERROR("Client code can adversely affect behavior: setter for " + property + "."); 1.218 + }, 1.219 + enumerable: false, 1.220 + configurable: true 1.221 + }); 1.222 +} 1.223 + 1.224 + 1.225 +/** 1.226 + * Taints a named method of the given object by replacing it with a function 1.227 + * that throws an exception. 1.228 + * @param {object} obj the object whose method to taint 1.229 + * @param {string} property the name of the method to taint 1.230 + */ 1.231 +function taintMethod(obj, property) { 1.232 + Object.defineProperty(obj, property, { 1.233 + value: function() { 1.234 + $ERROR("Client code can adversely affect behavior: method " + property + "."); 1.235 + }, 1.236 + writable: true, 1.237 + enumerable: false, 1.238 + configurable: true 1.239 + }); 1.240 +} 1.241 + 1.242 + 1.243 +/** 1.244 + * Taints the given properties (and similarly named properties) by installing 1.245 + * setters on Object.prototype that throw exceptions. 1.246 + * @param {Array} properties an array of property names to taint 1.247 + */ 1.248 +function taintProperties(properties) { 1.249 + properties.forEach(function (property) { 1.250 + var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"]; 1.251 + adaptedProperties.forEach(function (property) { 1.252 + taintDataProperty(Object.prototype, property); 1.253 + }); 1.254 + }); 1.255 +} 1.256 + 1.257 + 1.258 +/** 1.259 + * Taints the Array object by creating a setter for the property "0" and 1.260 + * replacing some key methods with functions that throw exceptions. 1.261 + */ 1.262 +function taintArray() { 1.263 + taintDataProperty(Array.prototype, "0"); 1.264 + taintMethod(Array.prototype, "indexOf"); 1.265 + taintMethod(Array.prototype, "join"); 1.266 + taintMethod(Array.prototype, "push"); 1.267 + taintMethod(Array.prototype, "slice"); 1.268 + taintMethod(Array.prototype, "sort"); 1.269 +} 1.270 + 1.271 + 1.272 +// auxiliary data for getLocaleSupportInfo 1.273 +var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"]; 1.274 +var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"]; 1.275 +var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"]; 1.276 +var localeSupportInfo = {}; 1.277 + 1.278 + 1.279 +/** 1.280 + * Gets locale support info for the given constructor object, which must be one 1.281 + * of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat. 1.282 + * @param {object} Constructor the constructor for which to get locale support info 1.283 + * @return {object} locale support info with the following properties: 1.284 + * supported: array of fully supported language tags 1.285 + * byFallback: array of language tags that are supported through fallbacks 1.286 + * unsupported: array of unsupported language tags 1.287 + */ 1.288 +function getLocaleSupportInfo(Constructor) { 1.289 + var constructorName = getConstructorName(Constructor); 1.290 + if (localeSupportInfo[constructorName] !== undefined) { 1.291 + return localeSupportInfo[constructorName]; 1.292 + } 1.293 + 1.294 + var allTags = []; 1.295 + var i, j, k; 1.296 + var language, script, country; 1.297 + for (i = 0; i < languages.length; i++) { 1.298 + language = languages[i]; 1.299 + allTags.push(language); 1.300 + for (j = 0; j < scripts.length; j++) { 1.301 + script = scripts[j]; 1.302 + allTags.push(language + "-" + script); 1.303 + for (k = 0; k < countries.length; k++) { 1.304 + country = countries[k]; 1.305 + allTags.push(language + "-" + script + "-" + country); 1.306 + } 1.307 + } 1.308 + for (k = 0; k < countries.length; k++) { 1.309 + country = countries[k]; 1.310 + allTags.push(language + "-" + country); 1.311 + } 1.312 + } 1.313 + 1.314 + var supported = []; 1.315 + var byFallback = []; 1.316 + var unsupported = []; 1.317 + for (i = 0; i < allTags.length; i++) { 1.318 + var request = allTags[i]; 1.319 + var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale; 1.320 + if (request === result) { 1.321 + supported.push(request); 1.322 + } else if (request.indexOf(result) === 0) { 1.323 + byFallback.push(request); 1.324 + } else { 1.325 + unsupported.push(request); 1.326 + } 1.327 + } 1.328 + 1.329 + localeSupportInfo[constructorName] = { 1.330 + supported: supported, 1.331 + byFallback: byFallback, 1.332 + unsupported: unsupported 1.333 + }; 1.334 + 1.335 + return localeSupportInfo[constructorName]; 1.336 +} 1.337 + 1.338 + 1.339 +/** 1.340 + * @description Tests whether locale is a String value representing a 1.341 + * structurally valid and canonicalized BCP 47 language tag, as defined in 1.342 + * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API 1.343 + * Specification. 1.344 + * @param {String} locale the string to be tested. 1.345 + * @result {Boolean} whether the test succeeded. 1.346 + */ 1.347 +function isCanonicalizedStructurallyValidLanguageTag(locale) { 1.348 + 1.349 + /** 1.350 + * Regular expression defining BCP 47 language tags. 1.351 + * 1.352 + * Spec: RFC 5646 section 2.1. 1.353 + */ 1.354 + var alpha = "[a-zA-Z]", 1.355 + digit = "[0-9]", 1.356 + alphanum = "(" + alpha + "|" + digit + ")", 1.357 + regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)", 1.358 + irregular = "(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)", 1.359 + grandfathered = "(" + irregular + "|" + regular + ")", 1.360 + privateuse = "(x(-[a-z0-9]{1,8})+)", 1.361 + singleton = "(" + digit + "|[A-WY-Za-wy-z])", 1.362 + extension = "(" + singleton + "(-" + alphanum + "{2,8})+)", 1.363 + variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))", 1.364 + region = "(" + alpha + "{2}|" + digit + "{3})", 1.365 + script = "(" + alpha + "{4})", 1.366 + extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})", 1.367 + language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})", 1.368 + langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?", 1.369 + languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$", 1.370 + languageTagRE = new RegExp(languageTag, "i"); 1.371 + var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")", 1.372 + duplicateSingletonRE = new RegExp(duplicateSingleton, "i"), 1.373 + duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")", 1.374 + duplicateVariantRE = new RegExp(duplicateVariant, "i"); 1.375 + 1.376 + 1.377 + /** 1.378 + * Verifies that the given string is a well-formed BCP 47 language tag 1.379 + * with no duplicate variant or singleton subtags. 1.380 + * 1.381 + * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2. 1.382 + */ 1.383 + function isStructurallyValidLanguageTag(locale) { 1.384 + if (!languageTagRE.test(locale)) { 1.385 + return false; 1.386 + } 1.387 + locale = locale.split(/-x-/)[0]; 1.388 + return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale); 1.389 + } 1.390 + 1.391 + 1.392 + /** 1.393 + * Mappings from complete tags to preferred values. 1.394 + * 1.395 + * Spec: IANA Language Subtag Registry. 1.396 + */ 1.397 + var __tagMappings = { 1.398 + // property names must be in lower case; values in canonical form 1.399 + 1.400 + // grandfathered tags from IANA language subtag registry, file date 2011-08-25 1.401 + "art-lojban": "jbo", 1.402 + "cel-gaulish": "cel-gaulish", 1.403 + "en-gb-oed": "en-GB-oed", 1.404 + "i-ami": "ami", 1.405 + "i-bnn": "bnn", 1.406 + "i-default": "i-default", 1.407 + "i-enochian": "i-enochian", 1.408 + "i-hak": "hak", 1.409 + "i-klingon": "tlh", 1.410 + "i-lux": "lb", 1.411 + "i-mingo": "i-mingo", 1.412 + "i-navajo": "nv", 1.413 + "i-pwn": "pwn", 1.414 + "i-tao": "tao", 1.415 + "i-tay": "tay", 1.416 + "i-tsu": "tsu", 1.417 + "no-bok": "nb", 1.418 + "no-nyn": "nn", 1.419 + "sgn-be-fr": "sfb", 1.420 + "sgn-be-nl": "vgt", 1.421 + "sgn-ch-de": "sgg", 1.422 + "zh-guoyu": "cmn", 1.423 + "zh-hakka": "hak", 1.424 + "zh-min": "zh-min", 1.425 + "zh-min-nan": "nan", 1.426 + "zh-xiang": "hsn", 1.427 + // deprecated redundant tags from IANA language subtag registry, file date 2011-08-25 1.428 + "sgn-br": "bzs", 1.429 + "sgn-co": "csn", 1.430 + "sgn-de": "gsg", 1.431 + "sgn-dk": "dsl", 1.432 + "sgn-es": "ssp", 1.433 + "sgn-fr": "fsl", 1.434 + "sgn-gb": "bfi", 1.435 + "sgn-gr": "gss", 1.436 + "sgn-ie": "isg", 1.437 + "sgn-it": "ise", 1.438 + "sgn-jp": "jsl", 1.439 + "sgn-mx": "mfs", 1.440 + "sgn-ni": "ncs", 1.441 + "sgn-nl": "dse", 1.442 + "sgn-no": "nsl", 1.443 + "sgn-pt": "psr", 1.444 + "sgn-se": "swl", 1.445 + "sgn-us": "ase", 1.446 + "sgn-za": "sfs", 1.447 + "zh-cmn": "cmn", 1.448 + "zh-cmn-hans": "cmn-Hans", 1.449 + "zh-cmn-hant": "cmn-Hant", 1.450 + "zh-gan": "gan", 1.451 + "zh-wuu": "wuu", 1.452 + "zh-yue": "yue", 1.453 + // deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25 1.454 + "ja-latn-hepburn-heploc": "ja-Latn-alalc97" 1.455 + }; 1.456 + 1.457 + 1.458 + /** 1.459 + * Mappings from non-extlang subtags to preferred values. 1.460 + * 1.461 + * Spec: IANA Language Subtag Registry. 1.462 + */ 1.463 + var __subtagMappings = { 1.464 + // property names and values must be in canonical case 1.465 + // language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 1.466 + "in": "id", 1.467 + "iw": "he", 1.468 + "ji": "yi", 1.469 + "jw": "jv", 1.470 + "mo": "ro", 1.471 + "ayx": "nun", 1.472 + "cjr": "mom", 1.473 + "cmk": "xch", 1.474 + "drh": "khk", 1.475 + "drw": "prs", 1.476 + "gav": "dev", 1.477 + "mst": "mry", 1.478 + "myt": "mry", 1.479 + "tie": "ras", 1.480 + "tkk": "twm", 1.481 + "tnf": "prs", 1.482 + // region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 1.483 + "BU": "MM", 1.484 + "DD": "DE", 1.485 + "FX": "FR", 1.486 + "TP": "TL", 1.487 + "YD": "YE", 1.488 + "ZR": "CD" 1.489 + }; 1.490 + 1.491 + 1.492 + /** 1.493 + * Mappings from extlang subtags to preferred values. 1.494 + * 1.495 + * Spec: IANA Language Subtag Registry. 1.496 + */ 1.497 + var __extlangMappings = { 1.498 + // extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 1.499 + // values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed 1.500 + "aao": ["aao", "ar"], 1.501 + "abh": ["abh", "ar"], 1.502 + "abv": ["abv", "ar"], 1.503 + "acm": ["acm", "ar"], 1.504 + "acq": ["acq", "ar"], 1.505 + "acw": ["acw", "ar"], 1.506 + "acx": ["acx", "ar"], 1.507 + "acy": ["acy", "ar"], 1.508 + "adf": ["adf", "ar"], 1.509 + "ads": ["ads", "sgn"], 1.510 + "aeb": ["aeb", "ar"], 1.511 + "aec": ["aec", "ar"], 1.512 + "aed": ["aed", "sgn"], 1.513 + "aen": ["aen", "sgn"], 1.514 + "afb": ["afb", "ar"], 1.515 + "afg": ["afg", "sgn"], 1.516 + "ajp": ["ajp", "ar"], 1.517 + "apc": ["apc", "ar"], 1.518 + "apd": ["apd", "ar"], 1.519 + "arb": ["arb", "ar"], 1.520 + "arq": ["arq", "ar"], 1.521 + "ars": ["ars", "ar"], 1.522 + "ary": ["ary", "ar"], 1.523 + "arz": ["arz", "ar"], 1.524 + "ase": ["ase", "sgn"], 1.525 + "asf": ["asf", "sgn"], 1.526 + "asp": ["asp", "sgn"], 1.527 + "asq": ["asq", "sgn"], 1.528 + "asw": ["asw", "sgn"], 1.529 + "auz": ["auz", "ar"], 1.530 + "avl": ["avl", "ar"], 1.531 + "ayh": ["ayh", "ar"], 1.532 + "ayl": ["ayl", "ar"], 1.533 + "ayn": ["ayn", "ar"], 1.534 + "ayp": ["ayp", "ar"], 1.535 + "bbz": ["bbz", "ar"], 1.536 + "bfi": ["bfi", "sgn"], 1.537 + "bfk": ["bfk", "sgn"], 1.538 + "bjn": ["bjn", "ms"], 1.539 + "bog": ["bog", "sgn"], 1.540 + "bqn": ["bqn", "sgn"], 1.541 + "bqy": ["bqy", "sgn"], 1.542 + "btj": ["btj", "ms"], 1.543 + "bve": ["bve", "ms"], 1.544 + "bvl": ["bvl", "sgn"], 1.545 + "bvu": ["bvu", "ms"], 1.546 + "bzs": ["bzs", "sgn"], 1.547 + "cdo": ["cdo", "zh"], 1.548 + "cds": ["cds", "sgn"], 1.549 + "cjy": ["cjy", "zh"], 1.550 + "cmn": ["cmn", "zh"], 1.551 + "coa": ["coa", "ms"], 1.552 + "cpx": ["cpx", "zh"], 1.553 + "csc": ["csc", "sgn"], 1.554 + "csd": ["csd", "sgn"], 1.555 + "cse": ["cse", "sgn"], 1.556 + "csf": ["csf", "sgn"], 1.557 + "csg": ["csg", "sgn"], 1.558 + "csl": ["csl", "sgn"], 1.559 + "csn": ["csn", "sgn"], 1.560 + "csq": ["csq", "sgn"], 1.561 + "csr": ["csr", "sgn"], 1.562 + "czh": ["czh", "zh"], 1.563 + "czo": ["czo", "zh"], 1.564 + "doq": ["doq", "sgn"], 1.565 + "dse": ["dse", "sgn"], 1.566 + "dsl": ["dsl", "sgn"], 1.567 + "dup": ["dup", "ms"], 1.568 + "ecs": ["ecs", "sgn"], 1.569 + "esl": ["esl", "sgn"], 1.570 + "esn": ["esn", "sgn"], 1.571 + "eso": ["eso", "sgn"], 1.572 + "eth": ["eth", "sgn"], 1.573 + "fcs": ["fcs", "sgn"], 1.574 + "fse": ["fse", "sgn"], 1.575 + "fsl": ["fsl", "sgn"], 1.576 + "fss": ["fss", "sgn"], 1.577 + "gan": ["gan", "zh"], 1.578 + "gom": ["gom", "kok"], 1.579 + "gse": ["gse", "sgn"], 1.580 + "gsg": ["gsg", "sgn"], 1.581 + "gsm": ["gsm", "sgn"], 1.582 + "gss": ["gss", "sgn"], 1.583 + "gus": ["gus", "sgn"], 1.584 + "hab": ["hab", "sgn"], 1.585 + "haf": ["haf", "sgn"], 1.586 + "hak": ["hak", "zh"], 1.587 + "hds": ["hds", "sgn"], 1.588 + "hji": ["hji", "ms"], 1.589 + "hks": ["hks", "sgn"], 1.590 + "hos": ["hos", "sgn"], 1.591 + "hps": ["hps", "sgn"], 1.592 + "hsh": ["hsh", "sgn"], 1.593 + "hsl": ["hsl", "sgn"], 1.594 + "hsn": ["hsn", "zh"], 1.595 + "icl": ["icl", "sgn"], 1.596 + "ils": ["ils", "sgn"], 1.597 + "inl": ["inl", "sgn"], 1.598 + "ins": ["ins", "sgn"], 1.599 + "ise": ["ise", "sgn"], 1.600 + "isg": ["isg", "sgn"], 1.601 + "isr": ["isr", "sgn"], 1.602 + "jak": ["jak", "ms"], 1.603 + "jax": ["jax", "ms"], 1.604 + "jcs": ["jcs", "sgn"], 1.605 + "jhs": ["jhs", "sgn"], 1.606 + "jls": ["jls", "sgn"], 1.607 + "jos": ["jos", "sgn"], 1.608 + "jsl": ["jsl", "sgn"], 1.609 + "jus": ["jus", "sgn"], 1.610 + "kgi": ["kgi", "sgn"], 1.611 + "knn": ["knn", "kok"], 1.612 + "kvb": ["kvb", "ms"], 1.613 + "kvk": ["kvk", "sgn"], 1.614 + "kvr": ["kvr", "ms"], 1.615 + "kxd": ["kxd", "ms"], 1.616 + "lbs": ["lbs", "sgn"], 1.617 + "lce": ["lce", "ms"], 1.618 + "lcf": ["lcf", "ms"], 1.619 + "liw": ["liw", "ms"], 1.620 + "lls": ["lls", "sgn"], 1.621 + "lsg": ["lsg", "sgn"], 1.622 + "lsl": ["lsl", "sgn"], 1.623 + "lso": ["lso", "sgn"], 1.624 + "lsp": ["lsp", "sgn"], 1.625 + "lst": ["lst", "sgn"], 1.626 + "lsy": ["lsy", "sgn"], 1.627 + "ltg": ["ltg", "lv"], 1.628 + "lvs": ["lvs", "lv"], 1.629 + "lzh": ["lzh", "zh"], 1.630 + "max": ["max", "ms"], 1.631 + "mdl": ["mdl", "sgn"], 1.632 + "meo": ["meo", "ms"], 1.633 + "mfa": ["mfa", "ms"], 1.634 + "mfb": ["mfb", "ms"], 1.635 + "mfs": ["mfs", "sgn"], 1.636 + "min": ["min", "ms"], 1.637 + "mnp": ["mnp", "zh"], 1.638 + "mqg": ["mqg", "ms"], 1.639 + "mre": ["mre", "sgn"], 1.640 + "msd": ["msd", "sgn"], 1.641 + "msi": ["msi", "ms"], 1.642 + "msr": ["msr", "sgn"], 1.643 + "mui": ["mui", "ms"], 1.644 + "mzc": ["mzc", "sgn"], 1.645 + "mzg": ["mzg", "sgn"], 1.646 + "mzy": ["mzy", "sgn"], 1.647 + "nan": ["nan", "zh"], 1.648 + "nbs": ["nbs", "sgn"], 1.649 + "ncs": ["ncs", "sgn"], 1.650 + "nsi": ["nsi", "sgn"], 1.651 + "nsl": ["nsl", "sgn"], 1.652 + "nsp": ["nsp", "sgn"], 1.653 + "nsr": ["nsr", "sgn"], 1.654 + "nzs": ["nzs", "sgn"], 1.655 + "okl": ["okl", "sgn"], 1.656 + "orn": ["orn", "ms"], 1.657 + "ors": ["ors", "ms"], 1.658 + "pel": ["pel", "ms"], 1.659 + "pga": ["pga", "ar"], 1.660 + "pks": ["pks", "sgn"], 1.661 + "prl": ["prl", "sgn"], 1.662 + "prz": ["prz", "sgn"], 1.663 + "psc": ["psc", "sgn"], 1.664 + "psd": ["psd", "sgn"], 1.665 + "pse": ["pse", "ms"], 1.666 + "psg": ["psg", "sgn"], 1.667 + "psl": ["psl", "sgn"], 1.668 + "pso": ["pso", "sgn"], 1.669 + "psp": ["psp", "sgn"], 1.670 + "psr": ["psr", "sgn"], 1.671 + "pys": ["pys", "sgn"], 1.672 + "rms": ["rms", "sgn"], 1.673 + "rsi": ["rsi", "sgn"], 1.674 + "rsl": ["rsl", "sgn"], 1.675 + "sdl": ["sdl", "sgn"], 1.676 + "sfb": ["sfb", "sgn"], 1.677 + "sfs": ["sfs", "sgn"], 1.678 + "sgg": ["sgg", "sgn"], 1.679 + "sgx": ["sgx", "sgn"], 1.680 + "shu": ["shu", "ar"], 1.681 + "slf": ["slf", "sgn"], 1.682 + "sls": ["sls", "sgn"], 1.683 + "sqs": ["sqs", "sgn"], 1.684 + "ssh": ["ssh", "ar"], 1.685 + "ssp": ["ssp", "sgn"], 1.686 + "ssr": ["ssr", "sgn"], 1.687 + "svk": ["svk", "sgn"], 1.688 + "swc": ["swc", "sw"], 1.689 + "swh": ["swh", "sw"], 1.690 + "swl": ["swl", "sgn"], 1.691 + "syy": ["syy", "sgn"], 1.692 + "tmw": ["tmw", "ms"], 1.693 + "tse": ["tse", "sgn"], 1.694 + "tsm": ["tsm", "sgn"], 1.695 + "tsq": ["tsq", "sgn"], 1.696 + "tss": ["tss", "sgn"], 1.697 + "tsy": ["tsy", "sgn"], 1.698 + "tza": ["tza", "sgn"], 1.699 + "ugn": ["ugn", "sgn"], 1.700 + "ugy": ["ugy", "sgn"], 1.701 + "ukl": ["ukl", "sgn"], 1.702 + "uks": ["uks", "sgn"], 1.703 + "urk": ["urk", "ms"], 1.704 + "uzn": ["uzn", "uz"], 1.705 + "uzs": ["uzs", "uz"], 1.706 + "vgt": ["vgt", "sgn"], 1.707 + "vkk": ["vkk", "ms"], 1.708 + "vkt": ["vkt", "ms"], 1.709 + "vsi": ["vsi", "sgn"], 1.710 + "vsl": ["vsl", "sgn"], 1.711 + "vsv": ["vsv", "sgn"], 1.712 + "wuu": ["wuu", "zh"], 1.713 + "xki": ["xki", "sgn"], 1.714 + "xml": ["xml", "sgn"], 1.715 + "xmm": ["xmm", "ms"], 1.716 + "xms": ["xms", "sgn"], 1.717 + "yds": ["yds", "sgn"], 1.718 + "ysl": ["ysl", "sgn"], 1.719 + "yue": ["yue", "zh"], 1.720 + "zib": ["zib", "sgn"], 1.721 + "zlm": ["zlm", "ms"], 1.722 + "zmi": ["zmi", "ms"], 1.723 + "zsl": ["zsl", "sgn"], 1.724 + "zsm": ["zsm", "ms"] 1.725 + }; 1.726 + 1.727 + 1.728 + /** 1.729 + * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags. 1.730 + * 1.731 + * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3. 1.732 + * Spec: RFC 5646, section 4.5. 1.733 + */ 1.734 + function canonicalizeLanguageTag(locale) { 1.735 + 1.736 + // start with lower case for easier processing, and because most subtags will need to be lower case anyway 1.737 + locale = locale.toLowerCase(); 1.738 + 1.739 + // handle mappings for complete tags 1.740 + if (__tagMappings.hasOwnProperty(locale)) { 1.741 + return __tagMappings[locale]; 1.742 + } 1.743 + 1.744 + var subtags = locale.split("-"); 1.745 + var i = 0; 1.746 + 1.747 + // handle standard part: all subtags before first singleton or "x" 1.748 + while (i < subtags.length) { 1.749 + var subtag = subtags[i]; 1.750 + if (subtag.length === 1 && (i > 0 || subtag === "x")) { 1.751 + break; 1.752 + } else if (i !== 0 && subtag.length === 2) { 1.753 + subtag = subtag.toUpperCase(); 1.754 + } else if (subtag.length === 4) { 1.755 + subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase(); 1.756 + } 1.757 + if (__subtagMappings.hasOwnProperty(subtag)) { 1.758 + subtag = __subtagMappings[subtag]; 1.759 + } else if (__extlangMappings.hasOwnProperty(subtag)) { 1.760 + subtag = __extlangMappings[subtag][0]; 1.761 + if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) { 1.762 + subtags.shift(); 1.763 + i--; 1.764 + } 1.765 + } 1.766 + subtags[i] = subtag; 1.767 + i++; 1.768 + } 1.769 + var normal = subtags.slice(0, i).join("-"); 1.770 + 1.771 + // handle extensions 1.772 + var extensions = []; 1.773 + while (i < subtags.length && subtags[i] !== "x") { 1.774 + var extensionStart = i; 1.775 + i++; 1.776 + while (i < subtags.length && subtags[i].length > 1) { 1.777 + i++; 1.778 + } 1.779 + var extension = subtags.slice(extensionStart, i).join("-"); 1.780 + extensions.push(extension); 1.781 + } 1.782 + extensions.sort(); 1.783 + 1.784 + // handle private use 1.785 + var privateUse; 1.786 + if (i < subtags.length) { 1.787 + privateUse = subtags.slice(i).join("-"); 1.788 + } 1.789 + 1.790 + // put everything back together 1.791 + var canonical = normal; 1.792 + if (extensions.length > 0) { 1.793 + canonical += "-" + extensions.join("-"); 1.794 + } 1.795 + if (privateUse !== undefined) { 1.796 + if (canonical.length > 0) { 1.797 + canonical += "-" + privateUse; 1.798 + } else { 1.799 + canonical = privateUse; 1.800 + } 1.801 + } 1.802 + 1.803 + return canonical; 1.804 + } 1.805 + 1.806 + return typeof locale === "string" && isStructurallyValidLanguageTag(locale) && 1.807 + canonicalizeLanguageTag(locale) === locale; 1.808 +} 1.809 + 1.810 + 1.811 +/** 1.812 + * Tests whether the named options property is correctly handled by the given constructor. 1.813 + * @param {object} Constructor the constructor to test. 1.814 + * @param {string} property the name of the options property to test. 1.815 + * @param {string} type the type that values of the property are expected to have 1.816 + * @param {Array} [values] an array of allowed values for the property. Not needed for boolean. 1.817 + * @param {any} fallback the fallback value that the property assumes if not provided. 1.818 + * @param {object} testOptions additional options: 1.819 + * @param {boolean} isOptional whether support for this property is optional for implementations. 1.820 + * @param {boolean} noReturn whether the resulting value of the property is not returned. 1.821 + * @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent. 1.822 + * @param {object} extra additional option to pass along, properties are value -> {option: value}. 1.823 + * @return {boolean} whether the test succeeded. 1.824 + */ 1.825 +function testOption(Constructor, property, type, values, fallback, testOptions) { 1.826 + var isOptional = testOptions !== undefined && testOptions.isOptional === true; 1.827 + var noReturn = testOptions !== undefined && testOptions.noReturn === true; 1.828 + var isILD = testOptions !== undefined && testOptions.isILD === true; 1.829 + 1.830 + function addExtraOptions(options, value, testOptions) { 1.831 + if (testOptions !== undefined && testOptions.extra !== undefined) { 1.832 + var extra; 1.833 + if (value !== undefined && testOptions.extra[value] !== undefined) { 1.834 + extra = testOptions.extra[value]; 1.835 + } else if (testOptions.extra.any !== undefined) { 1.836 + extra = testOptions.extra.any; 1.837 + } 1.838 + if (extra !== undefined) { 1.839 + Object.getOwnPropertyNames(extra).forEach(function (prop) { 1.840 + options[prop] = extra[prop]; 1.841 + }); 1.842 + } 1.843 + } 1.844 + } 1.845 + 1.846 + var testValues, options, obj, expected, actual, error; 1.847 + 1.848 + // test that the specified values are accepted. Also add values that convert to specified values. 1.849 + if (type === "boolean") { 1.850 + if (values === undefined) { 1.851 + values = [true, false]; 1.852 + } 1.853 + testValues = values.slice(0); 1.854 + testValues.push(888); 1.855 + testValues.push(0); 1.856 + } else if (type === "string") { 1.857 + testValues = values.slice(0); 1.858 + testValues.push({toString: function () { return values[0]; }}); 1.859 + } 1.860 + testValues.forEach(function (value) { 1.861 + options = {}; 1.862 + options[property] = value; 1.863 + addExtraOptions(options, value, testOptions); 1.864 + obj = new Constructor(undefined, options); 1.865 + if (noReturn) { 1.866 + if (obj.resolvedOptions().hasOwnProperty(property)) { 1.867 + $ERROR("Option property " + property + " is returned, but shouldn't be."); 1.868 + } 1.869 + } else { 1.870 + actual = obj.resolvedOptions()[property]; 1.871 + if (isILD) { 1.872 + if (actual !== undefined && values.indexOf(actual) === -1) { 1.873 + $ERROR("Invalid value " + actual + " returned for property " + property + "."); 1.874 + } 1.875 + } else { 1.876 + if (type === "boolean") { 1.877 + expected = Boolean(value); 1.878 + } else if (type === "string") { 1.879 + expected = String(value); 1.880 + } 1.881 + if (actual !== expected && !(isOptional && actual === undefined)) { 1.882 + $ERROR("Option value " + value + " for property " + property + 1.883 + " was not accepted; got " + actual + " instead."); 1.884 + } 1.885 + } 1.886 + } 1.887 + }); 1.888 + 1.889 + // test that invalid values are rejected 1.890 + if (type === "string") { 1.891 + var invalidValues = ["invalidValue", -1, null]; 1.892 + // assume that we won't have values in caseless scripts 1.893 + if (values[0].toUpperCase() !== values[0]) { 1.894 + invalidValues.push(values[0].toUpperCase()); 1.895 + } else { 1.896 + invalidValues.push(values[0].toLowerCase()); 1.897 + } 1.898 + invalidValues.forEach(function (value) { 1.899 + options = {}; 1.900 + options[property] = value; 1.901 + addExtraOptions(options, value, testOptions); 1.902 + error = undefined; 1.903 + try { 1.904 + obj = new Constructor(undefined, options); 1.905 + } catch (e) { 1.906 + error = e; 1.907 + } 1.908 + if (error === undefined) { 1.909 + $ERROR("Invalid option value " + value + " for property " + property + " was not rejected."); 1.910 + } else if (error.name !== "RangeError") { 1.911 + $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + "."); 1.912 + } 1.913 + }); 1.914 + } 1.915 + 1.916 + // test that fallback value or another valid value is used if no options value is provided 1.917 + if (!noReturn) { 1.918 + options = {}; 1.919 + addExtraOptions(options, undefined, testOptions); 1.920 + obj = new Constructor(undefined, options); 1.921 + actual = obj.resolvedOptions()[property]; 1.922 + if (!(isOptional && actual === undefined)) { 1.923 + if (fallback !== undefined) { 1.924 + if (actual !== fallback) { 1.925 + $ERROR("Option fallback value " + fallback + " for property " + property + 1.926 + " was not used; got " + actual + " instead."); 1.927 + } 1.928 + } else { 1.929 + if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) { 1.930 + $ERROR("Invalid value " + actual + " returned for property " + property + "."); 1.931 + } 1.932 + } 1.933 + } 1.934 + } 1.935 + 1.936 + return true; 1.937 +} 1.938 + 1.939 + 1.940 +/** 1.941 + * Tests whether the named property of the given object has a valid value 1.942 + * and the default attributes of the properties of an object literal. 1.943 + * @param {Object} obj the object to be tested. 1.944 + * @param {string} property the name of the property 1.945 + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, 1.946 + * an array of valid values. 1.947 + * @exception if the property has an invalid value. 1.948 + */ 1.949 +function testProperty(obj, property, valid) { 1.950 + var desc = Object.getOwnPropertyDescriptor(obj, property); 1.951 + if (!desc.writable) { 1.952 + $ERROR("Property " + property + " must be writable."); 1.953 + } 1.954 + if (!desc.enumerable) { 1.955 + $ERROR("Property " + property + " must be enumerable."); 1.956 + } 1.957 + if (!desc.configurable) { 1.958 + $ERROR("Property " + property + " must be configurable."); 1.959 + } 1.960 + var value = desc.value; 1.961 + var isValid = (typeof valid === "function") ? valid(value) : (valid.indexOf(value) !== -1); 1.962 + if (!isValid) { 1.963 + $ERROR("Property value " + value + " is not allowed for property " + property + "."); 1.964 + } 1.965 +} 1.966 + 1.967 + 1.968 +/** 1.969 + * Tests whether the named property of the given object, if present at all, has a valid value 1.970 + * and the default attributes of the properties of an object literal. 1.971 + * @param {Object} obj the object to be tested. 1.972 + * @param {string} property the name of the property 1.973 + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, 1.974 + * an array of valid values. 1.975 + * @exception if the property is present and has an invalid value. 1.976 + */ 1.977 +function mayHaveProperty(obj, property, valid) { 1.978 + if (obj.hasOwnProperty(property)) { 1.979 + testProperty(obj, property, valid); 1.980 + } 1.981 +} 1.982 + 1.983 + 1.984 +/** 1.985 + * Tests whether the given object has the named property with a valid value 1.986 + * and the default attributes of the properties of an object literal. 1.987 + * @param {Object} obj the object to be tested. 1.988 + * @param {string} property the name of the property 1.989 + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, 1.990 + * an array of valid values. 1.991 + * @exception if the property is missing or has an invalid value. 1.992 + */ 1.993 +function mustHaveProperty(obj, property, valid) { 1.994 + if (!obj.hasOwnProperty(property)) { 1.995 + $ERROR("Object is missing property " + property + "."); 1.996 + } 1.997 + testProperty(obj, property, valid); 1.998 +} 1.999 + 1.1000 + 1.1001 +/** 1.1002 + * Tests whether the given object does not have the named property. 1.1003 + * @param {Object} obj the object to be tested. 1.1004 + * @param {string} property the name of the property 1.1005 + * @exception if the property is present. 1.1006 + */ 1.1007 +function mustNotHaveProperty(obj, property) { 1.1008 + if (obj.hasOwnProperty(property)) { 1.1009 + $ERROR("Object has property it mustn't have: " + property + "."); 1.1010 + } 1.1011 +} 1.1012 + 1.1013 + 1.1014 +/** 1.1015 + * Properties of the RegExp constructor that may be affected by use of regular 1.1016 + * expressions, and the default values of these properties. Properties are from 1.1017 + * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties 1.1018 + */ 1.1019 +var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", 1.1020 + "$_", "$*", "$&", "$+", "$`", "$'", 1.1021 + "input", "lastMatch", "lastParen", "leftContext", "rightContext" 1.1022 +]; 1.1023 + 1.1024 +var regExpPropertiesDefaultValues = (function () { 1.1025 + var values = Object.create(null); 1.1026 + regExpProperties.forEach(function (property) { 1.1027 + values[property] = RegExp[property]; 1.1028 + }); 1.1029 + return values; 1.1030 +}()); 1.1031 + 1.1032 + 1.1033 +/** 1.1034 + * Tests that executing the provided function (which may use regular expressions 1.1035 + * in its implementation) does not create or modify unwanted properties on the 1.1036 + * RegExp constructor. 1.1037 + */ 1.1038 +function testForUnwantedRegExpChanges(testFunc) { 1.1039 + regExpProperties.forEach(function (property) { 1.1040 + RegExp[property] = regExpPropertiesDefaultValues[property]; 1.1041 + }); 1.1042 + testFunc(); 1.1043 + regExpProperties.forEach(function (property) { 1.1044 + if (RegExp[property] !== regExpPropertiesDefaultValues[property]) { 1.1045 + $ERROR("RegExp has unexpected property " + property + " with value " + 1.1046 + RegExp[property] + "."); 1.1047 + } 1.1048 + }); 1.1049 +} 1.1050 + 1.1051 + 1.1052 +/** 1.1053 + * Tests whether name is a valid BCP 47 numbering system name 1.1054 + * and not excluded from use in the ECMAScript Internationalization API. 1.1055 + * @param {string} name the name to be tested. 1.1056 + * @return {boolean} whether name is a valid BCP 47 numbering system name and 1.1057 + * allowed for use in the ECMAScript Internationalization API. 1.1058 + */ 1.1059 + 1.1060 +function isValidNumberingSystem(name) { 1.1061 + 1.1062 + // source: CLDR file common/bcp47/number.xml; version CLDR 21. 1.1063 + var numberingSystems = [ 1.1064 + "arab", 1.1065 + "arabext", 1.1066 + "armn", 1.1067 + "armnlow", 1.1068 + "bali", 1.1069 + "beng", 1.1070 + "brah", 1.1071 + "cakm", 1.1072 + "cham", 1.1073 + "deva", 1.1074 + "ethi", 1.1075 + "finance", 1.1076 + "fullwide", 1.1077 + "geor", 1.1078 + "grek", 1.1079 + "greklow", 1.1080 + "gujr", 1.1081 + "guru", 1.1082 + "hanidec", 1.1083 + "hans", 1.1084 + "hansfin", 1.1085 + "hant", 1.1086 + "hantfin", 1.1087 + "hebr", 1.1088 + "java", 1.1089 + "jpan", 1.1090 + "jpanfin", 1.1091 + "kali", 1.1092 + "khmr", 1.1093 + "knda", 1.1094 + "osma", 1.1095 + "lana", 1.1096 + "lanatham", 1.1097 + "laoo", 1.1098 + "latn", 1.1099 + "lepc", 1.1100 + "limb", 1.1101 + "mlym", 1.1102 + "mong", 1.1103 + "mtei", 1.1104 + "mymr", 1.1105 + "mymrshan", 1.1106 + "native", 1.1107 + "nkoo", 1.1108 + "olck", 1.1109 + "orya", 1.1110 + "roman", 1.1111 + "romanlow", 1.1112 + "saur", 1.1113 + "shrd", 1.1114 + "sora", 1.1115 + "sund", 1.1116 + "talu", 1.1117 + "takr", 1.1118 + "taml", 1.1119 + "tamldec", 1.1120 + "telu", 1.1121 + "thai", 1.1122 + "tibt", 1.1123 + "traditio", 1.1124 + "vaii" 1.1125 + ]; 1.1126 + 1.1127 + var excluded = [ 1.1128 + "finance", 1.1129 + "native", 1.1130 + "traditio" 1.1131 + ]; 1.1132 + 1.1133 + 1.1134 + return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1; 1.1135 +} 1.1136 + 1.1137 + 1.1138 +/** 1.1139 + * Provides the digits of numbering systems with simple digit mappings, 1.1140 + * as specified in 11.3.2. 1.1141 + */ 1.1142 + 1.1143 +var numberingSystemDigits = { 1.1144 + arab: "٠١٢٣٤٥٦٧٨٩", 1.1145 + arabext: "۰۱۲۳۴۵۶۷۸۹", 1.1146 + beng: "০১২৩৪৫৬৭৮৯", 1.1147 + deva: "०१२३४५६७८९", 1.1148 + fullwide: "0123456789", 1.1149 + gujr: "૦૧૨૩૪૫૬૭૮૯", 1.1150 + guru: "੦੧੨੩੪੫੬੭੮੯", 1.1151 + hanidec: "〇一二三四五六七八九", 1.1152 + khmr: "០១២៣៤៥៦៧៨៩", 1.1153 + knda: "೦೧೨೩೪೫೬೭೮೯", 1.1154 + laoo: "໐໑໒໓໔໕໖໗໘໙", 1.1155 + latn: "0123456789", 1.1156 + mlym: "൦൧൨൩൪൫൬൭൮൯", 1.1157 + mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙", 1.1158 + mymr: "၀၁၂၃၄၅၆၇၈၉", 1.1159 + orya: "୦୧୨୩୪୫୬୭୮୯", 1.1160 + tamldec: "௦௧௨௩௪௫௬௭௮௯", 1.1161 + telu: "౦౧౨౩౪౫౬౭౮౯", 1.1162 + thai: "๐๑๒๓๔๕๖๗๘๙", 1.1163 + tibt: "༠༡༢༣༤༥༦༧༨༩" 1.1164 +}; 1.1165 + 1.1166 + 1.1167 +/** 1.1168 + * Tests that number formatting is handled correctly. The function checks that the 1.1169 + * digit sequences in formatted output are as specified, converted to the 1.1170 + * selected numbering system, and embedded in consistent localized patterns. 1.1171 + * @param {Array} locales the locales to be tested. 1.1172 + * @param {Array} numberingSystems the numbering systems to be tested. 1.1173 + * @param {Object} options the options to pass to Intl.NumberFormat. Options 1.1174 + * must include {useGrouping: false}, and must cause 1.1 to be formatted 1.1175 + * pre- and post-decimal digits. 1.1176 + * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings 1.1177 + * in unlocalized format with Western digits. 1.1178 + */ 1.1179 + 1.1180 +function testNumberFormat(locales, numberingSystems, options, testData) { 1.1181 + locales.forEach(function (locale) { 1.1182 + numberingSystems.forEach(function (numbering) { 1.1183 + var digits = numberingSystemDigits[numbering]; 1.1184 + var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options); 1.1185 + 1.1186 + function getPatternParts(positive) { 1.1187 + var n = positive ? 1.1 : -1.1; 1.1188 + var formatted = format.format(n); 1.1189 + var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)"; 1.1190 + var match = formatted.match(new RegExp(oneoneRE)); 1.1191 + if (match === null) { 1.1192 + $ERROR("Unexpected formatted " + n + " for " + 1.1193 + format.resolvedOptions().locale + " and options " + 1.1194 + JSON.stringify(options) + ": " + formatted); 1.1195 + } 1.1196 + return match; 1.1197 + } 1.1198 + 1.1199 + function toNumbering(raw) { 1.1200 + return raw.replace(/[0-9]/g, function (digit) { 1.1201 + return digits[digit.charCodeAt(0) - "0".charCodeAt(0)]; 1.1202 + }); 1.1203 + } 1.1204 + 1.1205 + function buildExpected(raw, patternParts) { 1.1206 + var period = raw.indexOf("."); 1.1207 + if (period === -1) { 1.1208 + return patternParts[1] + toNumbering(raw) + patternParts[3]; 1.1209 + } else { 1.1210 + return patternParts[1] + 1.1211 + toNumbering(raw.substring(0, period)) + 1.1212 + patternParts[2] + 1.1213 + toNumbering(raw.substring(period + 1)) + 1.1214 + patternParts[3]; 1.1215 + } 1.1216 + } 1.1217 + 1.1218 + if (format.resolvedOptions().numberingSystem === numbering) { 1.1219 + // figure out prefixes, infixes, suffixes for positive and negative values 1.1220 + var posPatternParts = getPatternParts(true); 1.1221 + var negPatternParts = getPatternParts(false); 1.1222 + 1.1223 + Object.getOwnPropertyNames(testData).forEach(function (input) { 1.1224 + var rawExpected = testData[input]; 1.1225 + var patternParts; 1.1226 + if (rawExpected[0] === "-") { 1.1227 + patternParts = negPatternParts; 1.1228 + rawExpected = rawExpected.substring(1); 1.1229 + } else { 1.1230 + patternParts = posPatternParts; 1.1231 + } 1.1232 + var expected = buildExpected(rawExpected, patternParts); 1.1233 + var actual = format.format(input); 1.1234 + if (actual !== expected) { 1.1235 + $ERROR("Formatted value for " + input + ", " + 1.1236 + format.resolvedOptions().locale + " and options " + 1.1237 + JSON.stringify(options) + " is " + actual + "; expected " + expected + "."); 1.1238 + } 1.1239 + }); 1.1240 + } 1.1241 + }); 1.1242 + }); 1.1243 +} 1.1244 + 1.1245 + 1.1246 +/** 1.1247 + * Return the components of date-time formats. 1.1248 + * @return {Array} an array with all date-time components. 1.1249 + */ 1.1250 + 1.1251 +function getDateTimeComponents() { 1.1252 + return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"]; 1.1253 +} 1.1254 + 1.1255 + 1.1256 +/** 1.1257 + * Return the valid values for the given date-time component, as specified 1.1258 + * by the table in section 12.1.1. 1.1259 + * @param {string} component a date-time component. 1.1260 + * @return {Array} an array with the valid values for the component. 1.1261 + */ 1.1262 + 1.1263 +function getDateTimeComponentValues(component) { 1.1264 + 1.1265 + var components = { 1.1266 + weekday: ["narrow", "short", "long"], 1.1267 + era: ["narrow", "short", "long"], 1.1268 + year: ["2-digit", "numeric"], 1.1269 + month: ["2-digit", "numeric", "narrow", "short", "long"], 1.1270 + day: ["2-digit", "numeric"], 1.1271 + hour: ["2-digit", "numeric"], 1.1272 + minute: ["2-digit", "numeric"], 1.1273 + second: ["2-digit", "numeric"], 1.1274 + timeZoneName: ["short", "long"] 1.1275 + }; 1.1276 + 1.1277 + var result = components[component]; 1.1278 + if (result === undefined) { 1.1279 + $ERROR("Internal error: No values defined for date-time component " + component + "."); 1.1280 + } 1.1281 + return result; 1.1282 +} 1.1283 + 1.1284 + 1.1285 +/** 1.1286 + * Tests that the given value is valid for the given date-time component. 1.1287 + * @param {string} component a date-time component. 1.1288 + * @param {string} value the value to be tested. 1.1289 + * @return {boolean} true if the test succeeds. 1.1290 + * @exception if the test fails. 1.1291 + */ 1.1292 + 1.1293 +function testValidDateTimeComponentValue(component, value) { 1.1294 + if (getDateTimeComponentValues(component).indexOf(value) === -1) { 1.1295 + $ERROR("Invalid value " + value + " for date-time component " + component + "."); 1.1296 + } 1.1297 + return true; 1.1298 +} 1.1299 + 1.1300 + 1.1301 +/** 1.1302 + * Verifies that the actual array matches the expected one in length, elements, 1.1303 + * and element order. 1.1304 + * @param {Array} expected the expected array. 1.1305 + * @param {Array} actual the actual array. 1.1306 + * @return {boolean} true if the test succeeds. 1.1307 + * @exception if the test fails. 1.1308 + */ 1.1309 +function testArraysAreSame(expected, actual) { 1.1310 + for (i = 0; i < Math.max(actual.length, expected.length); i++) { 1.1311 + if (actual[i] !== expected[i]) { 1.1312 + $ERROR("Result array element at index " + i + " should be \"" + 1.1313 + expected[i] + "\" but is \"" + actual[i] + "\"."); 1.1314 + } 1.1315 + } 1.1316 + return true; 1.1317 +} 1.1318 +