js/src/tests/test262/intl402/browser.js

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

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 + ".");
  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] + ".");
  1045     });
  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;
  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);
  1193                 return match;
  1196             function toNumbering(raw) {
  1197                 return raw.replace(/[0-9]/g, function (digit) {
  1198                     return digits[digit.charCodeAt(0) - "0".charCodeAt(0)];
  1199                 });
  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];
  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;
  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 + ".");
  1236                 });
  1238         });
  1239     });
  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"];
  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 + ".");
  1278     return result;
  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 + ".");
  1294     return true;
  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] + "\".");
  1313     return true;

mercurial