Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * Undo at least the damage done by taintArray so that the jstests
7 * harness won't die. The properties added to Object.prototype by the various
8 * tests have names that are less likely to cause trouble.
9 */
10 setRestoreFunction((function () {
11 var Array_indexOf = Array.prototype.indexOf;
12 var Array_join = Array.prototype.join;
13 var Array_push = Array.prototype.push;
14 var Array_slice = Array.prototype.slice;
15 var Array_sort = Array.prototype.sort;
16 return function () {
17 delete Array.prototype["0"];
18 Array.prototype.indexOf = Array_indexOf;
19 Array.prototype.join = Array_join;
20 Array.prototype.push = Array_push;
21 Array.prototype.slice = Array_slice;
22 Array.prototype.sort = Array_sort;
23 };
24 }()));
25 // Copyright 2012 Mozilla Corporation. All rights reserved.
26 // This code is governed by the BSD license found in the LICENSE file.
28 /**
29 * @description Tests that obj meets the requirements for built-in objects
30 * defined by the introduction of chapter 15 of the ECMAScript Language Specification.
31 * @param {Object} obj the object to be tested.
32 * @param {boolean} isFunction whether the specification describes obj as a function.
33 * @param {boolean} isConstructor whether the specification describes obj as a constructor.
34 * @param {String[]} properties an array with the names of the built-in properties of obj,
35 * excluding length, prototype, or properties with non-default attributes.
36 * @param {number} length for functions only: the length specified for the function
37 * or derived from the argument list.
38 * @author Norbert Lindenberg
39 */
41 function testBuiltInObject(obj, isFunction, isConstructor, properties, length) {
43 if (obj === undefined) {
44 $ERROR("Object being tested is undefined.");
45 }
47 var objString = Object.prototype.toString.call(obj);
48 if (isFunction) {
49 if (objString !== "[object Function]") {
50 $ERROR("The [[Class]] internal property of a built-in function must be " +
51 "\"Function\", but toString() returns " + objString);
52 }
53 } else {
54 if (objString !== "[object Object]") {
55 $ERROR("The [[Class]] internal property of a built-in non-function object must be " +
56 "\"Object\", but toString() returns " + objString);
57 }
58 }
60 if (!Object.isExtensible(obj)) {
61 $ERROR("Built-in objects must be extensible.");
62 }
64 if (isFunction && Object.getPrototypeOf(obj) !== Function.prototype) {
65 $ERROR("Built-in functions must have Function.prototype as their prototype.");
66 }
68 if (isConstructor && Object.getPrototypeOf(obj.prototype) !== Object.prototype) {
69 $ERROR("Built-in prototype objects must have Object.prototype as their prototype.");
70 }
72 // verification of the absence of the [[Construct]] internal property has
73 // been moved to the end of the test
75 // verification of the absence of the prototype property has
76 // been moved to the end of the test
78 if (isFunction) {
80 if (typeof obj.length !== "number" || obj.length !== Math.floor(obj.length)) {
81 $ERROR("Built-in functions must have a length property with an integer value.");
82 }
84 if (obj.length !== length) {
85 $ERROR("Function's length property doesn't have specified value; expected " +
86 length + ", got " + obj.length + ".");
87 }
89 var desc = Object.getOwnPropertyDescriptor(obj, "length");
90 if (desc.writable) {
91 $ERROR("The length property of a built-in function must not be writable.");
92 }
93 if (desc.enumerable) {
94 $ERROR("The length property of a built-in function must not be enumerable.");
95 }
96 if (desc.configurable) {
97 $ERROR("The length property of a built-in function must not be configurable.");
98 }
99 }
101 properties.forEach(function(prop) {
102 var desc = Object.getOwnPropertyDescriptor(obj, prop);
103 if (desc === undefined) {
104 $ERROR("Missing property " + prop + ".");
105 }
106 // accessor properties don't have writable attribute
107 if (desc.hasOwnProperty("writable") && !desc.writable) {
108 $ERROR("The " + prop + " property of this built-in function must be writable.");
109 }
110 if (desc.enumerable) {
111 $ERROR("The " + prop + " property of this built-in function must not be enumerable.");
112 }
113 if (!desc.configurable) {
114 $ERROR("The " + prop + " property of this built-in function must be configurable.");
115 }
116 });
118 // The remaining sections have been moved to the end of the test because
119 // unbound non-constructor functions written in JavaScript cannot possibly
120 // pass them, and we still want to test JavaScript implementations as much
121 // as possible.
123 var exception;
124 if (isFunction && !isConstructor) {
125 // this is not a complete test for the presence of [[Construct]]:
126 // if it's absent, the exception must be thrown, but it may also
127 // be thrown if it's present and just has preconditions related to
128 // arguments or the this value that this statement doesn't meet.
129 try {
130 /*jshint newcap:false*/
131 var instance = new obj();
132 } catch (e) {
133 exception = e;
134 }
135 if (exception === undefined || exception.name !== "TypeError") {
136 $ERROR("Built-in functions that aren't constructors must throw TypeError when " +
137 "used in a \"new\" statement.");
138 }
139 }
141 if (isFunction && !isConstructor && obj.hasOwnProperty("prototype")) {
142 $ERROR("Built-in functions that aren't constructors must not have a prototype property.");
143 }
145 // passed the complete test!
146 return true;
147 }
149 // Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
150 // Copyright 2012-2013 Mozilla Corporation. All rights reserved.
151 // This code is governed by the BSD license found in the LICENSE file.
153 /**
154 * This file contains shared functions for the tests in the conformance test
155 * suite for the ECMAScript Internationalization API.
156 * @author Norbert Lindenberg
157 */
160 /**
161 * @description Calls the provided function for every service constructor in
162 * the Intl object, until f returns a falsy value. It returns the result of the
163 * last call to f, mapped to a boolean.
164 * @param {Function} f the function to call for each service constructor in
165 * the Intl object.
166 * @param {Function} Constructor the constructor object to test with.
167 * @result {Boolean} whether the test succeeded.
168 */
169 function testWithIntlConstructors(f) {
170 var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
171 return constructors.every(function (constructor) {
172 var Constructor = Intl[constructor];
173 var result;
174 try {
175 result = f(Constructor);
176 } catch (e) {
177 e.message += " (Testing with " + constructor + ".)";
178 throw e;
179 }
180 return result;
181 });
182 }
185 /**
186 * Returns the name of the given constructor object, which must be one of
187 * Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
188 * @param {object} Constructor a constructor
189 * @return {string} the name of the constructor
190 */
191 function getConstructorName(Constructor) {
192 switch (Constructor) {
193 case Intl.Collator:
194 return "Collator";
195 case Intl.NumberFormat:
196 return "NumberFormat";
197 case Intl.DateTimeFormat:
198 return "DateTimeFormat";
199 default:
200 $ERROR("test internal error: unknown Constructor");
201 }
202 }
205 /**
206 * Taints a named data property of the given object by installing
207 * a setter that throws an exception.
208 * @param {object} obj the object whose data property to taint
209 * @param {string} property the property to taint
210 */
211 function taintDataProperty(obj, property) {
212 Object.defineProperty(obj, property, {
213 set: function(value) {
214 $ERROR("Client code can adversely affect behavior: setter for " + property + ".");
215 },
216 enumerable: false,
217 configurable: true
218 });
219 }
222 /**
223 * Taints a named method of the given object by replacing it with a function
224 * that throws an exception.
225 * @param {object} obj the object whose method to taint
226 * @param {string} property the name of the method to taint
227 */
228 function taintMethod(obj, property) {
229 Object.defineProperty(obj, property, {
230 value: function() {
231 $ERROR("Client code can adversely affect behavior: method " + property + ".");
232 },
233 writable: true,
234 enumerable: false,
235 configurable: true
236 });
237 }
240 /**
241 * Taints the given properties (and similarly named properties) by installing
242 * setters on Object.prototype that throw exceptions.
243 * @param {Array} properties an array of property names to taint
244 */
245 function taintProperties(properties) {
246 properties.forEach(function (property) {
247 var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
248 adaptedProperties.forEach(function (property) {
249 taintDataProperty(Object.prototype, property);
250 });
251 });
252 }
255 /**
256 * Taints the Array object by creating a setter for the property "0" and
257 * replacing some key methods with functions that throw exceptions.
258 */
259 function taintArray() {
260 taintDataProperty(Array.prototype, "0");
261 taintMethod(Array.prototype, "indexOf");
262 taintMethod(Array.prototype, "join");
263 taintMethod(Array.prototype, "push");
264 taintMethod(Array.prototype, "slice");
265 taintMethod(Array.prototype, "sort");
266 }
269 // auxiliary data for getLocaleSupportInfo
270 var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
271 var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
272 var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
273 var localeSupportInfo = {};
276 /**
277 * Gets locale support info for the given constructor object, which must be one
278 * of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
279 * @param {object} Constructor the constructor for which to get locale support info
280 * @return {object} locale support info with the following properties:
281 * supported: array of fully supported language tags
282 * byFallback: array of language tags that are supported through fallbacks
283 * unsupported: array of unsupported language tags
284 */
285 function getLocaleSupportInfo(Constructor) {
286 var constructorName = getConstructorName(Constructor);
287 if (localeSupportInfo[constructorName] !== undefined) {
288 return localeSupportInfo[constructorName];
289 }
291 var allTags = [];
292 var i, j, k;
293 var language, script, country;
294 for (i = 0; i < languages.length; i++) {
295 language = languages[i];
296 allTags.push(language);
297 for (j = 0; j < scripts.length; j++) {
298 script = scripts[j];
299 allTags.push(language + "-" + script);
300 for (k = 0; k < countries.length; k++) {
301 country = countries[k];
302 allTags.push(language + "-" + script + "-" + country);
303 }
304 }
305 for (k = 0; k < countries.length; k++) {
306 country = countries[k];
307 allTags.push(language + "-" + country);
308 }
309 }
311 var supported = [];
312 var byFallback = [];
313 var unsupported = [];
314 for (i = 0; i < allTags.length; i++) {
315 var request = allTags[i];
316 var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
317 if (request === result) {
318 supported.push(request);
319 } else if (request.indexOf(result) === 0) {
320 byFallback.push(request);
321 } else {
322 unsupported.push(request);
323 }
324 }
326 localeSupportInfo[constructorName] = {
327 supported: supported,
328 byFallback: byFallback,
329 unsupported: unsupported
330 };
332 return localeSupportInfo[constructorName];
333 }
336 /**
337 * @description Tests whether locale is a String value representing a
338 * structurally valid and canonicalized BCP 47 language tag, as defined in
339 * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
340 * Specification.
341 * @param {String} locale the string to be tested.
342 * @result {Boolean} whether the test succeeded.
343 */
344 function isCanonicalizedStructurallyValidLanguageTag(locale) {
346 /**
347 * Regular expression defining BCP 47 language tags.
348 *
349 * Spec: RFC 5646 section 2.1.
350 */
351 var alpha = "[a-zA-Z]",
352 digit = "[0-9]",
353 alphanum = "(" + alpha + "|" + digit + ")",
354 regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
355 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)",
356 grandfathered = "(" + irregular + "|" + regular + ")",
357 privateuse = "(x(-[a-z0-9]{1,8})+)",
358 singleton = "(" + digit + "|[A-WY-Za-wy-z])",
359 extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
360 variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
361 region = "(" + alpha + "{2}|" + digit + "{3})",
362 script = "(" + alpha + "{4})",
363 extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
364 language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
365 langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
366 languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
367 languageTagRE = new RegExp(languageTag, "i");
368 var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
369 duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
370 duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
371 duplicateVariantRE = new RegExp(duplicateVariant, "i");
374 /**
375 * Verifies that the given string is a well-formed BCP 47 language tag
376 * with no duplicate variant or singleton subtags.
377 *
378 * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
379 */
380 function isStructurallyValidLanguageTag(locale) {
381 if (!languageTagRE.test(locale)) {
382 return false;
383 }
384 locale = locale.split(/-x-/)[0];
385 return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
386 }
389 /**
390 * Mappings from complete tags to preferred values.
391 *
392 * Spec: IANA Language Subtag Registry.
393 */
394 var __tagMappings = {
395 // property names must be in lower case; values in canonical form
397 // grandfathered tags from IANA language subtag registry, file date 2011-08-25
398 "art-lojban": "jbo",
399 "cel-gaulish": "cel-gaulish",
400 "en-gb-oed": "en-GB-oed",
401 "i-ami": "ami",
402 "i-bnn": "bnn",
403 "i-default": "i-default",
404 "i-enochian": "i-enochian",
405 "i-hak": "hak",
406 "i-klingon": "tlh",
407 "i-lux": "lb",
408 "i-mingo": "i-mingo",
409 "i-navajo": "nv",
410 "i-pwn": "pwn",
411 "i-tao": "tao",
412 "i-tay": "tay",
413 "i-tsu": "tsu",
414 "no-bok": "nb",
415 "no-nyn": "nn",
416 "sgn-be-fr": "sfb",
417 "sgn-be-nl": "vgt",
418 "sgn-ch-de": "sgg",
419 "zh-guoyu": "cmn",
420 "zh-hakka": "hak",
421 "zh-min": "zh-min",
422 "zh-min-nan": "nan",
423 "zh-xiang": "hsn",
424 // deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
425 "sgn-br": "bzs",
426 "sgn-co": "csn",
427 "sgn-de": "gsg",
428 "sgn-dk": "dsl",
429 "sgn-es": "ssp",
430 "sgn-fr": "fsl",
431 "sgn-gb": "bfi",
432 "sgn-gr": "gss",
433 "sgn-ie": "isg",
434 "sgn-it": "ise",
435 "sgn-jp": "jsl",
436 "sgn-mx": "mfs",
437 "sgn-ni": "ncs",
438 "sgn-nl": "dse",
439 "sgn-no": "nsl",
440 "sgn-pt": "psr",
441 "sgn-se": "swl",
442 "sgn-us": "ase",
443 "sgn-za": "sfs",
444 "zh-cmn": "cmn",
445 "zh-cmn-hans": "cmn-Hans",
446 "zh-cmn-hant": "cmn-Hant",
447 "zh-gan": "gan",
448 "zh-wuu": "wuu",
449 "zh-yue": "yue",
450 // deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
451 "ja-latn-hepburn-heploc": "ja-Latn-alalc97"
452 };
455 /**
456 * Mappings from non-extlang subtags to preferred values.
457 *
458 * Spec: IANA Language Subtag Registry.
459 */
460 var __subtagMappings = {
461 // property names and values must be in canonical case
462 // language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
463 "in": "id",
464 "iw": "he",
465 "ji": "yi",
466 "jw": "jv",
467 "mo": "ro",
468 "ayx": "nun",
469 "cjr": "mom",
470 "cmk": "xch",
471 "drh": "khk",
472 "drw": "prs",
473 "gav": "dev",
474 "mst": "mry",
475 "myt": "mry",
476 "tie": "ras",
477 "tkk": "twm",
478 "tnf": "prs",
479 // region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
480 "BU": "MM",
481 "DD": "DE",
482 "FX": "FR",
483 "TP": "TL",
484 "YD": "YE",
485 "ZR": "CD"
486 };
489 /**
490 * Mappings from extlang subtags to preferred values.
491 *
492 * Spec: IANA Language Subtag Registry.
493 */
494 var __extlangMappings = {
495 // extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
496 // values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
497 "aao": ["aao", "ar"],
498 "abh": ["abh", "ar"],
499 "abv": ["abv", "ar"],
500 "acm": ["acm", "ar"],
501 "acq": ["acq", "ar"],
502 "acw": ["acw", "ar"],
503 "acx": ["acx", "ar"],
504 "acy": ["acy", "ar"],
505 "adf": ["adf", "ar"],
506 "ads": ["ads", "sgn"],
507 "aeb": ["aeb", "ar"],
508 "aec": ["aec", "ar"],
509 "aed": ["aed", "sgn"],
510 "aen": ["aen", "sgn"],
511 "afb": ["afb", "ar"],
512 "afg": ["afg", "sgn"],
513 "ajp": ["ajp", "ar"],
514 "apc": ["apc", "ar"],
515 "apd": ["apd", "ar"],
516 "arb": ["arb", "ar"],
517 "arq": ["arq", "ar"],
518 "ars": ["ars", "ar"],
519 "ary": ["ary", "ar"],
520 "arz": ["arz", "ar"],
521 "ase": ["ase", "sgn"],
522 "asf": ["asf", "sgn"],
523 "asp": ["asp", "sgn"],
524 "asq": ["asq", "sgn"],
525 "asw": ["asw", "sgn"],
526 "auz": ["auz", "ar"],
527 "avl": ["avl", "ar"],
528 "ayh": ["ayh", "ar"],
529 "ayl": ["ayl", "ar"],
530 "ayn": ["ayn", "ar"],
531 "ayp": ["ayp", "ar"],
532 "bbz": ["bbz", "ar"],
533 "bfi": ["bfi", "sgn"],
534 "bfk": ["bfk", "sgn"],
535 "bjn": ["bjn", "ms"],
536 "bog": ["bog", "sgn"],
537 "bqn": ["bqn", "sgn"],
538 "bqy": ["bqy", "sgn"],
539 "btj": ["btj", "ms"],
540 "bve": ["bve", "ms"],
541 "bvl": ["bvl", "sgn"],
542 "bvu": ["bvu", "ms"],
543 "bzs": ["bzs", "sgn"],
544 "cdo": ["cdo", "zh"],
545 "cds": ["cds", "sgn"],
546 "cjy": ["cjy", "zh"],
547 "cmn": ["cmn", "zh"],
548 "coa": ["coa", "ms"],
549 "cpx": ["cpx", "zh"],
550 "csc": ["csc", "sgn"],
551 "csd": ["csd", "sgn"],
552 "cse": ["cse", "sgn"],
553 "csf": ["csf", "sgn"],
554 "csg": ["csg", "sgn"],
555 "csl": ["csl", "sgn"],
556 "csn": ["csn", "sgn"],
557 "csq": ["csq", "sgn"],
558 "csr": ["csr", "sgn"],
559 "czh": ["czh", "zh"],
560 "czo": ["czo", "zh"],
561 "doq": ["doq", "sgn"],
562 "dse": ["dse", "sgn"],
563 "dsl": ["dsl", "sgn"],
564 "dup": ["dup", "ms"],
565 "ecs": ["ecs", "sgn"],
566 "esl": ["esl", "sgn"],
567 "esn": ["esn", "sgn"],
568 "eso": ["eso", "sgn"],
569 "eth": ["eth", "sgn"],
570 "fcs": ["fcs", "sgn"],
571 "fse": ["fse", "sgn"],
572 "fsl": ["fsl", "sgn"],
573 "fss": ["fss", "sgn"],
574 "gan": ["gan", "zh"],
575 "gom": ["gom", "kok"],
576 "gse": ["gse", "sgn"],
577 "gsg": ["gsg", "sgn"],
578 "gsm": ["gsm", "sgn"],
579 "gss": ["gss", "sgn"],
580 "gus": ["gus", "sgn"],
581 "hab": ["hab", "sgn"],
582 "haf": ["haf", "sgn"],
583 "hak": ["hak", "zh"],
584 "hds": ["hds", "sgn"],
585 "hji": ["hji", "ms"],
586 "hks": ["hks", "sgn"],
587 "hos": ["hos", "sgn"],
588 "hps": ["hps", "sgn"],
589 "hsh": ["hsh", "sgn"],
590 "hsl": ["hsl", "sgn"],
591 "hsn": ["hsn", "zh"],
592 "icl": ["icl", "sgn"],
593 "ils": ["ils", "sgn"],
594 "inl": ["inl", "sgn"],
595 "ins": ["ins", "sgn"],
596 "ise": ["ise", "sgn"],
597 "isg": ["isg", "sgn"],
598 "isr": ["isr", "sgn"],
599 "jak": ["jak", "ms"],
600 "jax": ["jax", "ms"],
601 "jcs": ["jcs", "sgn"],
602 "jhs": ["jhs", "sgn"],
603 "jls": ["jls", "sgn"],
604 "jos": ["jos", "sgn"],
605 "jsl": ["jsl", "sgn"],
606 "jus": ["jus", "sgn"],
607 "kgi": ["kgi", "sgn"],
608 "knn": ["knn", "kok"],
609 "kvb": ["kvb", "ms"],
610 "kvk": ["kvk", "sgn"],
611 "kvr": ["kvr", "ms"],
612 "kxd": ["kxd", "ms"],
613 "lbs": ["lbs", "sgn"],
614 "lce": ["lce", "ms"],
615 "lcf": ["lcf", "ms"],
616 "liw": ["liw", "ms"],
617 "lls": ["lls", "sgn"],
618 "lsg": ["lsg", "sgn"],
619 "lsl": ["lsl", "sgn"],
620 "lso": ["lso", "sgn"],
621 "lsp": ["lsp", "sgn"],
622 "lst": ["lst", "sgn"],
623 "lsy": ["lsy", "sgn"],
624 "ltg": ["ltg", "lv"],
625 "lvs": ["lvs", "lv"],
626 "lzh": ["lzh", "zh"],
627 "max": ["max", "ms"],
628 "mdl": ["mdl", "sgn"],
629 "meo": ["meo", "ms"],
630 "mfa": ["mfa", "ms"],
631 "mfb": ["mfb", "ms"],
632 "mfs": ["mfs", "sgn"],
633 "min": ["min", "ms"],
634 "mnp": ["mnp", "zh"],
635 "mqg": ["mqg", "ms"],
636 "mre": ["mre", "sgn"],
637 "msd": ["msd", "sgn"],
638 "msi": ["msi", "ms"],
639 "msr": ["msr", "sgn"],
640 "mui": ["mui", "ms"],
641 "mzc": ["mzc", "sgn"],
642 "mzg": ["mzg", "sgn"],
643 "mzy": ["mzy", "sgn"],
644 "nan": ["nan", "zh"],
645 "nbs": ["nbs", "sgn"],
646 "ncs": ["ncs", "sgn"],
647 "nsi": ["nsi", "sgn"],
648 "nsl": ["nsl", "sgn"],
649 "nsp": ["nsp", "sgn"],
650 "nsr": ["nsr", "sgn"],
651 "nzs": ["nzs", "sgn"],
652 "okl": ["okl", "sgn"],
653 "orn": ["orn", "ms"],
654 "ors": ["ors", "ms"],
655 "pel": ["pel", "ms"],
656 "pga": ["pga", "ar"],
657 "pks": ["pks", "sgn"],
658 "prl": ["prl", "sgn"],
659 "prz": ["prz", "sgn"],
660 "psc": ["psc", "sgn"],
661 "psd": ["psd", "sgn"],
662 "pse": ["pse", "ms"],
663 "psg": ["psg", "sgn"],
664 "psl": ["psl", "sgn"],
665 "pso": ["pso", "sgn"],
666 "psp": ["psp", "sgn"],
667 "psr": ["psr", "sgn"],
668 "pys": ["pys", "sgn"],
669 "rms": ["rms", "sgn"],
670 "rsi": ["rsi", "sgn"],
671 "rsl": ["rsl", "sgn"],
672 "sdl": ["sdl", "sgn"],
673 "sfb": ["sfb", "sgn"],
674 "sfs": ["sfs", "sgn"],
675 "sgg": ["sgg", "sgn"],
676 "sgx": ["sgx", "sgn"],
677 "shu": ["shu", "ar"],
678 "slf": ["slf", "sgn"],
679 "sls": ["sls", "sgn"],
680 "sqs": ["sqs", "sgn"],
681 "ssh": ["ssh", "ar"],
682 "ssp": ["ssp", "sgn"],
683 "ssr": ["ssr", "sgn"],
684 "svk": ["svk", "sgn"],
685 "swc": ["swc", "sw"],
686 "swh": ["swh", "sw"],
687 "swl": ["swl", "sgn"],
688 "syy": ["syy", "sgn"],
689 "tmw": ["tmw", "ms"],
690 "tse": ["tse", "sgn"],
691 "tsm": ["tsm", "sgn"],
692 "tsq": ["tsq", "sgn"],
693 "tss": ["tss", "sgn"],
694 "tsy": ["tsy", "sgn"],
695 "tza": ["tza", "sgn"],
696 "ugn": ["ugn", "sgn"],
697 "ugy": ["ugy", "sgn"],
698 "ukl": ["ukl", "sgn"],
699 "uks": ["uks", "sgn"],
700 "urk": ["urk", "ms"],
701 "uzn": ["uzn", "uz"],
702 "uzs": ["uzs", "uz"],
703 "vgt": ["vgt", "sgn"],
704 "vkk": ["vkk", "ms"],
705 "vkt": ["vkt", "ms"],
706 "vsi": ["vsi", "sgn"],
707 "vsl": ["vsl", "sgn"],
708 "vsv": ["vsv", "sgn"],
709 "wuu": ["wuu", "zh"],
710 "xki": ["xki", "sgn"],
711 "xml": ["xml", "sgn"],
712 "xmm": ["xmm", "ms"],
713 "xms": ["xms", "sgn"],
714 "yds": ["yds", "sgn"],
715 "ysl": ["ysl", "sgn"],
716 "yue": ["yue", "zh"],
717 "zib": ["zib", "sgn"],
718 "zlm": ["zlm", "ms"],
719 "zmi": ["zmi", "ms"],
720 "zsl": ["zsl", "sgn"],
721 "zsm": ["zsm", "ms"]
722 };
725 /**
726 * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
727 *
728 * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
729 * Spec: RFC 5646, section 4.5.
730 */
731 function canonicalizeLanguageTag(locale) {
733 // start with lower case for easier processing, and because most subtags will need to be lower case anyway
734 locale = locale.toLowerCase();
736 // handle mappings for complete tags
737 if (__tagMappings.hasOwnProperty(locale)) {
738 return __tagMappings[locale];
739 }
741 var subtags = locale.split("-");
742 var i = 0;
744 // handle standard part: all subtags before first singleton or "x"
745 while (i < subtags.length) {
746 var subtag = subtags[i];
747 if (subtag.length === 1 && (i > 0 || subtag === "x")) {
748 break;
749 } else if (i !== 0 && subtag.length === 2) {
750 subtag = subtag.toUpperCase();
751 } else if (subtag.length === 4) {
752 subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
753 }
754 if (__subtagMappings.hasOwnProperty(subtag)) {
755 subtag = __subtagMappings[subtag];
756 } else if (__extlangMappings.hasOwnProperty(subtag)) {
757 subtag = __extlangMappings[subtag][0];
758 if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
759 subtags.shift();
760 i--;
761 }
762 }
763 subtags[i] = subtag;
764 i++;
765 }
766 var normal = subtags.slice(0, i).join("-");
768 // handle extensions
769 var extensions = [];
770 while (i < subtags.length && subtags[i] !== "x") {
771 var extensionStart = i;
772 i++;
773 while (i < subtags.length && subtags[i].length > 1) {
774 i++;
775 }
776 var extension = subtags.slice(extensionStart, i).join("-");
777 extensions.push(extension);
778 }
779 extensions.sort();
781 // handle private use
782 var privateUse;
783 if (i < subtags.length) {
784 privateUse = subtags.slice(i).join("-");
785 }
787 // put everything back together
788 var canonical = normal;
789 if (extensions.length > 0) {
790 canonical += "-" + extensions.join("-");
791 }
792 if (privateUse !== undefined) {
793 if (canonical.length > 0) {
794 canonical += "-" + privateUse;
795 } else {
796 canonical = privateUse;
797 }
798 }
800 return canonical;
801 }
803 return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
804 canonicalizeLanguageTag(locale) === locale;
805 }
808 /**
809 * Tests whether the named options property is correctly handled by the given constructor.
810 * @param {object} Constructor the constructor to test.
811 * @param {string} property the name of the options property to test.
812 * @param {string} type the type that values of the property are expected to have
813 * @param {Array} [values] an array of allowed values for the property. Not needed for boolean.
814 * @param {any} fallback the fallback value that the property assumes if not provided.
815 * @param {object} testOptions additional options:
816 * @param {boolean} isOptional whether support for this property is optional for implementations.
817 * @param {boolean} noReturn whether the resulting value of the property is not returned.
818 * @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent.
819 * @param {object} extra additional option to pass along, properties are value -> {option: value}.
820 * @return {boolean} whether the test succeeded.
821 */
822 function testOption(Constructor, property, type, values, fallback, testOptions) {
823 var isOptional = testOptions !== undefined && testOptions.isOptional === true;
824 var noReturn = testOptions !== undefined && testOptions.noReturn === true;
825 var isILD = testOptions !== undefined && testOptions.isILD === true;
827 function addExtraOptions(options, value, testOptions) {
828 if (testOptions !== undefined && testOptions.extra !== undefined) {
829 var extra;
830 if (value !== undefined && testOptions.extra[value] !== undefined) {
831 extra = testOptions.extra[value];
832 } else if (testOptions.extra.any !== undefined) {
833 extra = testOptions.extra.any;
834 }
835 if (extra !== undefined) {
836 Object.getOwnPropertyNames(extra).forEach(function (prop) {
837 options[prop] = extra[prop];
838 });
839 }
840 }
841 }
843 var testValues, options, obj, expected, actual, error;
845 // test that the specified values are accepted. Also add values that convert to specified values.
846 if (type === "boolean") {
847 if (values === undefined) {
848 values = [true, false];
849 }
850 testValues = values.slice(0);
851 testValues.push(888);
852 testValues.push(0);
853 } else if (type === "string") {
854 testValues = values.slice(0);
855 testValues.push({toString: function () { return values[0]; }});
856 }
857 testValues.forEach(function (value) {
858 options = {};
859 options[property] = value;
860 addExtraOptions(options, value, testOptions);
861 obj = new Constructor(undefined, options);
862 if (noReturn) {
863 if (obj.resolvedOptions().hasOwnProperty(property)) {
864 $ERROR("Option property " + property + " is returned, but shouldn't be.");
865 }
866 } else {
867 actual = obj.resolvedOptions()[property];
868 if (isILD) {
869 if (actual !== undefined && values.indexOf(actual) === -1) {
870 $ERROR("Invalid value " + actual + " returned for property " + property + ".");
871 }
872 } else {
873 if (type === "boolean") {
874 expected = Boolean(value);
875 } else if (type === "string") {
876 expected = String(value);
877 }
878 if (actual !== expected && !(isOptional && actual === undefined)) {
879 $ERROR("Option value " + value + " for property " + property +
880 " was not accepted; got " + actual + " instead.");
881 }
882 }
883 }
884 });
886 // test that invalid values are rejected
887 if (type === "string") {
888 var invalidValues = ["invalidValue", -1, null];
889 // assume that we won't have values in caseless scripts
890 if (values[0].toUpperCase() !== values[0]) {
891 invalidValues.push(values[0].toUpperCase());
892 } else {
893 invalidValues.push(values[0].toLowerCase());
894 }
895 invalidValues.forEach(function (value) {
896 options = {};
897 options[property] = value;
898 addExtraOptions(options, value, testOptions);
899 error = undefined;
900 try {
901 obj = new Constructor(undefined, options);
902 } catch (e) {
903 error = e;
904 }
905 if (error === undefined) {
906 $ERROR("Invalid option value " + value + " for property " + property + " was not rejected.");
907 } else if (error.name !== "RangeError") {
908 $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + ".");
909 }
910 });
911 }
913 // test that fallback value or another valid value is used if no options value is provided
914 if (!noReturn) {
915 options = {};
916 addExtraOptions(options, undefined, testOptions);
917 obj = new Constructor(undefined, options);
918 actual = obj.resolvedOptions()[property];
919 if (!(isOptional && actual === undefined)) {
920 if (fallback !== undefined) {
921 if (actual !== fallback) {
922 $ERROR("Option fallback value " + fallback + " for property " + property +
923 " was not used; got " + actual + " instead.");
924 }
925 } else {
926 if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) {
927 $ERROR("Invalid value " + actual + " returned for property " + property + ".");
928 }
929 }
930 }
931 }
933 return true;
934 }
937 /**
938 * Tests whether the named property of the given object has a valid value
939 * and the default attributes of the properties of an object literal.
940 * @param {Object} obj the object to be tested.
941 * @param {string} property the name of the property
942 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
943 * an array of valid values.
944 * @exception if the property has an invalid value.
945 */
946 function testProperty(obj, property, valid) {
947 var desc = Object.getOwnPropertyDescriptor(obj, property);
948 if (!desc.writable) {
949 $ERROR("Property " + property + " must be writable.");
950 }
951 if (!desc.enumerable) {
952 $ERROR("Property " + property + " must be enumerable.");
953 }
954 if (!desc.configurable) {
955 $ERROR("Property " + property + " must be configurable.");
956 }
957 var value = desc.value;
958 var isValid = (typeof valid === "function") ? valid(value) : (valid.indexOf(value) !== -1);
959 if (!isValid) {
960 $ERROR("Property value " + value + " is not allowed for property " + property + ".");
961 }
962 }
965 /**
966 * Tests whether the named property of the given object, if present at all, has a valid value
967 * and the default attributes of the properties of an object literal.
968 * @param {Object} obj the object to be tested.
969 * @param {string} property the name of the property
970 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
971 * an array of valid values.
972 * @exception if the property is present and has an invalid value.
973 */
974 function mayHaveProperty(obj, property, valid) {
975 if (obj.hasOwnProperty(property)) {
976 testProperty(obj, property, valid);
977 }
978 }
981 /**
982 * Tests whether the given object has the named property with a valid value
983 * and the default attributes of the properties of an object literal.
984 * @param {Object} obj the object to be tested.
985 * @param {string} property the name of the property
986 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
987 * an array of valid values.
988 * @exception if the property is missing or has an invalid value.
989 */
990 function mustHaveProperty(obj, property, valid) {
991 if (!obj.hasOwnProperty(property)) {
992 $ERROR("Object is missing property " + property + ".");
993 }
994 testProperty(obj, property, valid);
995 }
998 /**
999 * Tests whether the given object does not have the named property.
1000 * @param {Object} obj the object to be tested.
1001 * @param {string} property the name of the property
1002 * @exception if the property is present.
1003 */
1004 function mustNotHaveProperty(obj, property) {
1005 if (obj.hasOwnProperty(property)) {
1006 $ERROR("Object has property it mustn't have: " + property + ".");
1007 }
1008 }
1011 /**
1012 * Properties of the RegExp constructor that may be affected by use of regular
1013 * expressions, and the default values of these properties. Properties are from
1014 * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties
1015 */
1016 var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
1017 "$_", "$*", "$&", "$+", "$`", "$'",
1018 "input", "lastMatch", "lastParen", "leftContext", "rightContext"
1019 ];
1021 var regExpPropertiesDefaultValues = (function () {
1022 var values = Object.create(null);
1023 regExpProperties.forEach(function (property) {
1024 values[property] = RegExp[property];
1025 });
1026 return values;
1027 }());
1030 /**
1031 * Tests that executing the provided function (which may use regular expressions
1032 * in its implementation) does not create or modify unwanted properties on the
1033 * RegExp constructor.
1034 */
1035 function testForUnwantedRegExpChanges(testFunc) {
1036 regExpProperties.forEach(function (property) {
1037 RegExp[property] = regExpPropertiesDefaultValues[property];
1038 });
1039 testFunc();
1040 regExpProperties.forEach(function (property) {
1041 if (RegExp[property] !== regExpPropertiesDefaultValues[property]) {
1042 $ERROR("RegExp has unexpected property " + property + " with value " +
1043 RegExp[property] + ".");
1044 }
1045 });
1046 }
1049 /**
1050 * Tests whether name is a valid BCP 47 numbering system name
1051 * and not excluded from use in the ECMAScript Internationalization API.
1052 * @param {string} name the name to be tested.
1053 * @return {boolean} whether name is a valid BCP 47 numbering system name and
1054 * allowed for use in the ECMAScript Internationalization API.
1055 */
1057 function isValidNumberingSystem(name) {
1059 // source: CLDR file common/bcp47/number.xml; version CLDR 21.
1060 var numberingSystems = [
1061 "arab",
1062 "arabext",
1063 "armn",
1064 "armnlow",
1065 "bali",
1066 "beng",
1067 "brah",
1068 "cakm",
1069 "cham",
1070 "deva",
1071 "ethi",
1072 "finance",
1073 "fullwide",
1074 "geor",
1075 "grek",
1076 "greklow",
1077 "gujr",
1078 "guru",
1079 "hanidec",
1080 "hans",
1081 "hansfin",
1082 "hant",
1083 "hantfin",
1084 "hebr",
1085 "java",
1086 "jpan",
1087 "jpanfin",
1088 "kali",
1089 "khmr",
1090 "knda",
1091 "osma",
1092 "lana",
1093 "lanatham",
1094 "laoo",
1095 "latn",
1096 "lepc",
1097 "limb",
1098 "mlym",
1099 "mong",
1100 "mtei",
1101 "mymr",
1102 "mymrshan",
1103 "native",
1104 "nkoo",
1105 "olck",
1106 "orya",
1107 "roman",
1108 "romanlow",
1109 "saur",
1110 "shrd",
1111 "sora",
1112 "sund",
1113 "talu",
1114 "takr",
1115 "taml",
1116 "tamldec",
1117 "telu",
1118 "thai",
1119 "tibt",
1120 "traditio",
1121 "vaii"
1122 ];
1124 var excluded = [
1125 "finance",
1126 "native",
1127 "traditio"
1128 ];
1131 return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1;
1132 }
1135 /**
1136 * Provides the digits of numbering systems with simple digit mappings,
1137 * as specified in 11.3.2.
1138 */
1140 var numberingSystemDigits = {
1141 arab: "٠١٢٣٤٥٦٧٨٩",
1142 arabext: "۰۱۲۳۴۵۶۷۸۹",
1143 beng: "০১২৩৪৫৬৭৮৯",
1144 deva: "०१२३४५६७८९",
1145 fullwide: "0123456789",
1146 gujr: "૦૧૨૩૪૫૬૭૮૯",
1147 guru: "੦੧੨੩੪੫੬੭੮੯",
1148 hanidec: "〇一二三四五六七八九",
1149 khmr: "០១២៣៤៥៦៧៨៩",
1150 knda: "೦೧೨೩೪೫೬೭೮೯",
1151 laoo: "໐໑໒໓໔໕໖໗໘໙",
1152 latn: "0123456789",
1153 mlym: "൦൧൨൩൪൫൬൭൮൯",
1154 mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙",
1155 mymr: "၀၁၂၃၄၅၆၇၈၉",
1156 orya: "୦୧୨୩୪୫୬୭୮୯",
1157 tamldec: "௦௧௨௩௪௫௬௭௮௯",
1158 telu: "౦౧౨౩౪౫౬౭౮౯",
1159 thai: "๐๑๒๓๔๕๖๗๘๙",
1160 tibt: "༠༡༢༣༤༥༦༧༨༩"
1161 };
1164 /**
1165 * Tests that number formatting is handled correctly. The function checks that the
1166 * digit sequences in formatted output are as specified, converted to the
1167 * selected numbering system, and embedded in consistent localized patterns.
1168 * @param {Array} locales the locales to be tested.
1169 * @param {Array} numberingSystems the numbering systems to be tested.
1170 * @param {Object} options the options to pass to Intl.NumberFormat. Options
1171 * must include {useGrouping: false}, and must cause 1.1 to be formatted
1172 * pre- and post-decimal digits.
1173 * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings
1174 * in unlocalized format with Western digits.
1175 */
1177 function testNumberFormat(locales, numberingSystems, options, testData) {
1178 locales.forEach(function (locale) {
1179 numberingSystems.forEach(function (numbering) {
1180 var digits = numberingSystemDigits[numbering];
1181 var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options);
1183 function getPatternParts(positive) {
1184 var n = positive ? 1.1 : -1.1;
1185 var formatted = format.format(n);
1186 var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)";
1187 var match = formatted.match(new RegExp(oneoneRE));
1188 if (match === null) {
1189 $ERROR("Unexpected formatted " + n + " for " +
1190 format.resolvedOptions().locale + " and options " +
1191 JSON.stringify(options) + ": " + formatted);
1192 }
1193 return match;
1194 }
1196 function toNumbering(raw) {
1197 return raw.replace(/[0-9]/g, function (digit) {
1198 return digits[digit.charCodeAt(0) - "0".charCodeAt(0)];
1199 });
1200 }
1202 function buildExpected(raw, patternParts) {
1203 var period = raw.indexOf(".");
1204 if (period === -1) {
1205 return patternParts[1] + toNumbering(raw) + patternParts[3];
1206 } else {
1207 return patternParts[1] +
1208 toNumbering(raw.substring(0, period)) +
1209 patternParts[2] +
1210 toNumbering(raw.substring(period + 1)) +
1211 patternParts[3];
1212 }
1213 }
1215 if (format.resolvedOptions().numberingSystem === numbering) {
1216 // figure out prefixes, infixes, suffixes for positive and negative values
1217 var posPatternParts = getPatternParts(true);
1218 var negPatternParts = getPatternParts(false);
1220 Object.getOwnPropertyNames(testData).forEach(function (input) {
1221 var rawExpected = testData[input];
1222 var patternParts;
1223 if (rawExpected[0] === "-") {
1224 patternParts = negPatternParts;
1225 rawExpected = rawExpected.substring(1);
1226 } else {
1227 patternParts = posPatternParts;
1228 }
1229 var expected = buildExpected(rawExpected, patternParts);
1230 var actual = format.format(input);
1231 if (actual !== expected) {
1232 $ERROR("Formatted value for " + input + ", " +
1233 format.resolvedOptions().locale + " and options " +
1234 JSON.stringify(options) + " is " + actual + "; expected " + expected + ".");
1235 }
1236 });
1237 }
1238 });
1239 });
1240 }
1243 /**
1244 * Return the components of date-time formats.
1245 * @return {Array} an array with all date-time components.
1246 */
1248 function getDateTimeComponents() {
1249 return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
1250 }
1253 /**
1254 * Return the valid values for the given date-time component, as specified
1255 * by the table in section 12.1.1.
1256 * @param {string} component a date-time component.
1257 * @return {Array} an array with the valid values for the component.
1258 */
1260 function getDateTimeComponentValues(component) {
1262 var components = {
1263 weekday: ["narrow", "short", "long"],
1264 era: ["narrow", "short", "long"],
1265 year: ["2-digit", "numeric"],
1266 month: ["2-digit", "numeric", "narrow", "short", "long"],
1267 day: ["2-digit", "numeric"],
1268 hour: ["2-digit", "numeric"],
1269 minute: ["2-digit", "numeric"],
1270 second: ["2-digit", "numeric"],
1271 timeZoneName: ["short", "long"]
1272 };
1274 var result = components[component];
1275 if (result === undefined) {
1276 $ERROR("Internal error: No values defined for date-time component " + component + ".");
1277 }
1278 return result;
1279 }
1282 /**
1283 * Tests that the given value is valid for the given date-time component.
1284 * @param {string} component a date-time component.
1285 * @param {string} value the value to be tested.
1286 * @return {boolean} true if the test succeeds.
1287 * @exception if the test fails.
1288 */
1290 function testValidDateTimeComponentValue(component, value) {
1291 if (getDateTimeComponentValues(component).indexOf(value) === -1) {
1292 $ERROR("Invalid value " + value + " for date-time component " + component + ".");
1293 }
1294 return true;
1295 }
1298 /**
1299 * Verifies that the actual array matches the expected one in length, elements,
1300 * and element order.
1301 * @param {Array} expected the expected array.
1302 * @param {Array} actual the actual array.
1303 * @return {boolean} true if the test succeeds.
1304 * @exception if the test fails.
1305 */
1306 function testArraysAreSame(expected, actual) {
1307 for (i = 0; i < Math.max(actual.length, expected.length); i++) {
1308 if (actual[i] !== expected[i]) {
1309 $ERROR("Result array element at index " + i + " should be \"" +
1310 expected[i] + "\" but is \"" + actual[i] + "\".");
1311 }
1312 }
1313 return true;
1314 }