summaryrefslogtreecommitdiffstats
path: root/js/src/tests/supporting
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/supporting')
-rw-r--r--js/src/tests/supporting/README9
-rw-r--r--js/src/tests/supporting/sta.js901
-rw-r--r--js/src/tests/supporting/test262-browser.js11
-rw-r--r--js/src/tests/supporting/test262-shell.js39
-rw-r--r--js/src/tests/supporting/test402-browser.js24
-rw-r--r--js/src/tests/supporting/test402-shell.js10
-rw-r--r--js/src/tests/supporting/testBuiltInObject.js124
-rw-r--r--js/src/tests/supporting/testIntl.js1167
8 files changed, 2285 insertions, 0 deletions
diff --git a/js/src/tests/supporting/README b/js/src/tests/supporting/README
new file mode 100644
index 000000000..477b216b6
--- /dev/null
+++ b/js/src/tests/supporting/README
@@ -0,0 +1,9 @@
+================================
+= DANGER!!!!!!!!1!!!cos(0)!!!! =
+================================
+
+Any *.js files you add in this directory *will* be considered to be tests by the
+test-staging Makefile target, used to package up JS tests for running on
+Tinderbox. You are now probably sorry this is the case. But there is a
+hackaround! To make the packaging algorithm ignore a *.js file here, add it to
+the EXCLUDED set in lib/manifest.py.
diff --git a/js/src/tests/supporting/sta.js b/js/src/tests/supporting/sta.js
new file mode 100644
index 000000000..5380639e0
--- /dev/null
+++ b/js/src/tests/supporting/sta.js
@@ -0,0 +1,901 @@
+/// Copyright (c) 2012 Ecma International. All rights reserved.
+/// Ecma International makes this code available under the terms and conditions set
+/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the
+/// "Use Terms"). Any redistribution of this code must retain the above
+/// copyright and this notice and otherwise comply with the Use Terms.
+
+//-----------------------------------------------------------------------------
+function compareArray(aExpected, aActual) {
+ if (aActual.length != aExpected.length) {
+ return false;
+ }
+
+ aExpected.sort();
+ aActual.sort();
+
+ var s;
+ for (var i = 0; i < aExpected.length; i++) {
+ if (aActual[i] !== aExpected[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+function arrayContains(arr, expected) {
+ var found;
+ for (var i = 0; i < expected.length; i++) {
+ found = false;
+ for (var j = 0; j < arr.length; j++) {
+ if (expected[i] === arr[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+var supportsArrayIndexGettersOnArrays = undefined;
+function fnSupportsArrayIndexGettersOnArrays() {
+ if (typeof supportsArrayIndexGettersOnArrays !== "undefined") {
+ return supportsArrayIndexGettersOnArrays;
+ }
+
+ supportsArrayIndexGettersOnArrays = false;
+
+ if (fnExists(Object.defineProperty)) {
+ var arr = [];
+ Object.defineProperty(arr, "0", {
+ get: function() {
+ supportsArrayIndexGettersOnArrays = true;
+ return 0;
+ }
+ });
+ var res = arr[0];
+ }
+
+ return supportsArrayIndexGettersOnArrays;
+}
+
+//-----------------------------------------------------------------------------
+var supportsArrayIndexGettersOnObjects = undefined;
+function fnSupportsArrayIndexGettersOnObjects() {
+ if (typeof supportsArrayIndexGettersOnObjects !== "undefined")
+ return supportsArrayIndexGettersOnObjects;
+
+ supportsArrayIndexGettersOnObjects = false;
+
+ if (fnExists(Object.defineProperty)) {
+ var obj = {};
+ Object.defineProperty(obj, "0", {
+ get: function() {
+ supportsArrayIndexGettersOnObjects = true;
+ return 0;
+ }
+ });
+ var res = obj[0];
+ }
+
+ return supportsArrayIndexGettersOnObjects;
+}
+
+//-----------------------------------------------------------------------------
+function ConvertToFileUrl(pathStr) {
+ return "file:" + pathStr.replace(/\\/g, "/");
+}
+
+//-----------------------------------------------------------------------------
+function fnExists(/*arguments*/) {
+ for (var i = 0; i < arguments.length; i++) {
+ if (typeof (arguments[i]) !== "function") return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+var __globalObject = Function("return this;")();
+function fnGlobalObject() {
+ return __globalObject;
+}
+
+//-----------------------------------------------------------------------------
+function fnSupportsStrict() {
+ "use strict";
+ try {
+ eval('with ({}) {}');
+ return false;
+ } catch (e) {
+ return true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//Verify all attributes specified data property of given object:
+//value, writable, enumerable, configurable
+//If all attribute values are expected, return true, otherwise, return false
+function dataPropertyAttributesAreCorrect(obj,
+ name,
+ value,
+ writable,
+ enumerable,
+ configurable) {
+ var attributesCorrect = true;
+
+ if (obj[name] !== value) {
+ if (typeof obj[name] === "number" &&
+ isNaN(obj[name]) &&
+ typeof value === "number" &&
+ isNaN(value)) {
+ // keep empty
+ } else {
+ attributesCorrect = false;
+ }
+ }
+
+ try {
+ if (obj[name] === "oldValue") {
+ obj[name] = "newValue";
+ } else {
+ obj[name] = "OldValue";
+ }
+ } catch (we) {
+ }
+
+ var overwrited = false;
+ if (obj[name] !== value) {
+ if (typeof obj[name] === "number" &&
+ isNaN(obj[name]) &&
+ typeof value === "number" &&
+ isNaN(value)) {
+ // keep empty
+ } else {
+ overwrited = true;
+ }
+ }
+ if (overwrited !== writable) {
+ attributesCorrect = false;
+ }
+
+ var enumerated = false;
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop) && prop === name) {
+ enumerated = true;
+ }
+ }
+
+ if (enumerated !== enumerable) {
+ attributesCorrect = false;
+ }
+
+
+ var deleted = false;
+
+ try {
+ delete obj[name];
+ } catch (de) {
+ }
+ if (!obj.hasOwnProperty(name)) {
+ deleted = true;
+ }
+ if (deleted !== configurable) {
+ attributesCorrect = false;
+ }
+
+ return attributesCorrect;
+}
+
+//-----------------------------------------------------------------------------
+//Verify all attributes specified accessor property of given object:
+//get, set, enumerable, configurable
+//If all attribute values are expected, return true, otherwise, return false
+function accessorPropertyAttributesAreCorrect(obj,
+ name,
+ get,
+ set,
+ setVerifyHelpProp,
+ enumerable,
+ configurable) {
+ var attributesCorrect = true;
+
+ if (get !== undefined) {
+ if (obj[name] !== get()) {
+ if (typeof obj[name] === "number" &&
+ isNaN(obj[name]) &&
+ typeof get() === "number" &&
+ isNaN(get())) {
+ // keep empty
+ } else {
+ attributesCorrect = false;
+ }
+ }
+ } else {
+ if (obj[name] !== undefined) {
+ attributesCorrect = false;
+ }
+ }
+
+ try {
+ var desc = Object.getOwnPropertyDescriptor(obj, name);
+ if (typeof desc.set === "undefined") {
+ if (typeof set !== "undefined") {
+ attributesCorrect = false;
+ }
+ } else {
+ obj[name] = "toBeSetValue";
+ if (obj[setVerifyHelpProp] !== "toBeSetValue") {
+ attributesCorrect = false;
+ }
+ }
+ } catch (se) {
+ throw se;
+ }
+
+
+ var enumerated = false;
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop) && prop === name) {
+ enumerated = true;
+ }
+ }
+
+ if (enumerated !== enumerable) {
+ attributesCorrect = false;
+ }
+
+
+ var deleted = false;
+ try {
+ delete obj[name];
+ } catch (de) {
+ throw de;
+ }
+ if (!obj.hasOwnProperty(name)) {
+ deleted = true;
+ }
+ if (deleted !== configurable) {
+ attributesCorrect = false;
+ }
+
+ return attributesCorrect;
+}
+
+//-----------------------------------------------------------------------------
+var NotEarlyErrorString = "NotEarlyError";
+var EarlyErrorRePat = "^((?!" + NotEarlyErrorString + ").)*$";
+var NotEarlyError = new Error(NotEarlyErrorString);
+
+//-----------------------------------------------------------------------------
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function Test262Error(message) {
+ if (message) this.message = message;
+}
+
+Test262Error.prototype.toString = function () {
+ return "Test262 Error: " + this.message;
+};
+
+function testFailed(message) {
+ throw new Test262Error(message);
+}
+
+
+function testPrint(message) {
+
+}
+
+
+//adaptors for Test262 framework
+function $PRINT(message) {
+
+}
+
+function $INCLUDE(message) { }
+function $ERROR(message) {
+ testFailed(message);
+}
+
+function $FAIL(message) {
+ testFailed(message);
+}
+
+
+
+//Sputnik library definitions
+//Ultimately these should be namespaced some how and only made
+//available to tests that explicitly include them.
+//For now, we just define the globally
+
+//math_precision.js
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function getPrecision(num) {
+ //TODO: Create a table of prec's,
+ // because using Math for testing Math isn't that correct.
+
+ var log2num = Math.log(Math.abs(num)) / Math.LN2;
+ var pernum = Math.ceil(log2num);
+ return (2 * Math.pow(2, -52 + pernum));
+ //return(0);
+}
+
+
+//math_isequal.js
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+var prec;
+function isEqual(num1, num2) {
+ if ((num1 === Infinity) && (num2 === Infinity)) {
+ return (true);
+ }
+ if ((num1 === -Infinity) && (num2 === -Infinity)) {
+ return (true);
+ }
+ prec = getPrecision(Math.min(Math.abs(num1), Math.abs(num2)));
+ return (Math.abs(num1 - num2) <= prec);
+ //return(num1 === num2);
+}
+
+//numeric_conversion.js
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function ToInteger(p) {
+ var x = Number(p);
+
+ if (isNaN(x)) {
+ return +0;
+ }
+
+ if ((x === +0)
+ || (x === -0)
+ || (x === Number.POSITIVE_INFINITY)
+ || (x === Number.NEGATIVE_INFINITY)) {
+ return x;
+ }
+
+ var sign = (x < 0) ? -1 : 1;
+
+ return (sign * Math.floor(Math.abs(x)));
+}
+
+//Date_constants.js
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+var HoursPerDay = 24;
+var MinutesPerHour = 60;
+var SecondsPerMinute = 60;
+
+var msPerDay = 86400000;
+var msPerSecond = 1000;
+var msPerMinute = 60000;
+var msPerHour = 3600000;
+
+var date_1899_end = -2208988800001;
+var date_1900_start = -2208988800000;
+var date_1969_end = -1;
+var date_1970_start = 0;
+var date_1999_end = 946684799999;
+var date_2000_start = 946684800000;
+var date_2099_end = 4102444799999;
+var date_2100_start = 4102444800000;
+
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+//the following values are normally generated by the sputnik.py driver
+var $LocalTZ,
+ $DST_start_month,
+ $DST_start_sunday,
+ $DST_start_hour,
+ $DST_start_minutes,
+ $DST_end_month,
+ $DST_end_sunday,
+ $DST_end_hour,
+ $DST_end_minutes;
+
+(function () {
+ /**
+ * Finds the first date, starting from |start|, where |predicate|
+ * holds.
+ */
+ var findNearestDateBefore = function(start, predicate) {
+ var current = start;
+ var month = 1000 * 60 * 60 * 24 * 30;
+ for (var step = month; step > 0; step = Math.floor(step / 3)) {
+ if (!predicate(current)) {
+ while (!predicate(current))
+ current = new Date(current.getTime() + step);
+ current = new Date(current.getTime() - step);
+ }
+ }
+ while (!predicate(current)) {
+ current = new Date(current.getTime() + 1);
+ }
+ return current;
+ };
+
+ var juneDate = new Date(2000, 5, 20, 0, 0, 0, 0);
+ var decemberDate = new Date(2000, 11, 20, 0, 0, 0, 0);
+ var juneOffset = juneDate.getTimezoneOffset();
+ var decemberOffset = decemberDate.getTimezoneOffset();
+ var isSouthernHemisphere = (juneOffset > decemberOffset);
+ var winterTime = isSouthernHemisphere ? juneDate : decemberDate;
+ var summerTime = isSouthernHemisphere ? decemberDate : juneDate;
+
+ var dstStart = findNearestDateBefore(winterTime, function (date) {
+ return date.getTimezoneOffset() == summerTime.getTimezoneOffset();
+ });
+ $DST_start_month = dstStart.getMonth();
+ $DST_start_sunday = dstStart.getDate() > 15 ? '"last"' : '"first"';
+ $DST_start_hour = dstStart.getHours();
+ $DST_start_minutes = dstStart.getMinutes();
+
+ var dstEnd = findNearestDateBefore(summerTime, function (date) {
+ return date.getTimezoneOffset() == winterTime.getTimezoneOffset();
+ });
+ $DST_end_month = dstEnd.getMonth();
+ $DST_end_sunday = dstEnd.getDate() > 15 ? '"last"' : '"first"';
+ $DST_end_hour = dstEnd.getHours();
+ $DST_end_minutes = dstEnd.getMinutes();
+
+ return;
+})();
+
+
+//Date.library.js
+// Copyright 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+//15.9.1.2 Day Number and Time within Day
+function Day(t) {
+ return Math.floor(t/msPerDay);
+}
+
+function TimeWithinDay(t) {
+ return t%msPerDay;
+}
+
+//15.9.1.3 Year Number
+function DaysInYear(y){
+ if(y%4 != 0) return 365;
+ if(y%4 == 0 && y%100 != 0) return 366;
+ if(y%100 == 0 && y%400 != 0) return 365;
+ if(y%400 == 0) return 366;
+}
+
+function DayFromYear(y) {
+ return (365*(y-1970)
+ + Math.floor((y-1969)/4)
+ - Math.floor((y-1901)/100)
+ + Math.floor((y-1601)/400));
+}
+
+function TimeFromYear(y){
+ return msPerDay*DayFromYear(y);
+}
+
+function YearFromTime(t) {
+ t = Number(t);
+ var sign = ( t < 0 ) ? -1 : 1;
+ var year = ( sign < 0 ) ? 1969 : 1970;
+
+ for(var time = 0;;year += sign){
+ time = TimeFromYear(year);
+
+ if(sign > 0 && time > t){
+ year -= sign;
+ break;
+ }
+ else if(sign < 0 && time <= t){
+ break;
+ }
+ };
+ return year;
+}
+
+function InLeapYear(t){
+ if(DaysInYear(YearFromTime(t)) == 365)
+ return 0;
+
+ if(DaysInYear(YearFromTime(t)) == 366)
+ return 1;
+}
+
+function DayWithinYear(t) {
+ return Day(t)-DayFromYear(YearFromTime(t));
+}
+
+//15.9.1.4 Month Number
+function MonthFromTime(t){
+ var day = DayWithinYear(t);
+ var leap = InLeapYear(t);
+
+ if((0 <= day) && (day < 31)) return 0;
+ if((31 <= day) && (day < (59+leap))) return 1;
+ if(((59+leap) <= day) && (day < (90+leap))) return 2;
+ if(((90+leap) <= day) && (day < (120+leap))) return 3;
+ if(((120+leap) <= day) && (day < (151+leap))) return 4;
+ if(((151+leap) <= day) && (day < (181+leap))) return 5;
+ if(((181+leap) <= day) && (day < (212+leap))) return 6;
+ if(((212+leap) <= day) && (day < (243+leap))) return 7;
+ if(((243+leap) <= day) && (day < (273+leap))) return 8;
+ if(((273+leap) <= day) && (day < (304+leap))) return 9;
+ if(((304+leap) <= day) && (day < (334+leap))) return 10;
+ if(((334+leap) <= day) && (day < (365+leap))) return 11;
+}
+
+//15.9.1.5 Date Number
+function DateFromTime(t) {
+ var day = DayWithinYear(t);
+ var month = MonthFromTime(t);
+ var leap = InLeapYear(t);
+
+ if(month == 0) return day+1;
+ if(month == 1) return day-30;
+ if(month == 2) return day-58-leap;
+ if(month == 3) return day-89-leap;
+ if(month == 4) return day-119-leap;
+ if(month == 5) return day-150-leap;
+ if(month == 6) return day-180-leap;
+ if(month == 7) return day-211-leap;
+ if(month == 8) return day-242-leap;
+ if(month == 9) return day-272-leap;
+ if(month == 10) return day-303-leap;
+ if(month == 11) return day-333-leap;
+}
+
+//15.9.1.6 Week Day
+function WeekDay(t) {
+ var weekday = (Day(t)+4)%7;
+ return (weekday < 0 ? 7+weekday : weekday);
+}
+
+//15.9.1.9 Daylight Saving Time Adjustment
+$LocalTZ = (new Date()).getTimezoneOffset() / -60;
+if (DaylightSavingTA((new Date()).valueOf()) !== 0) {
+ $LocalTZ -= 1;
+}
+var LocalTZA = $LocalTZ*msPerHour;
+
+function DaysInMonth(m, leap) {
+ m = m%12;
+
+ //April, June, Sept, Nov
+ if(m == 3 || m == 5 || m == 8 || m == 10 ) {
+ return 30;
+ }
+
+ //Jan, March, May, July, Aug, Oct, Dec
+ if(m == 0 || m == 2 || m == 4 || m == 6 || m == 7 || m == 9 || m == 11){
+ return 31;
+ }
+
+ //Feb
+ return 28+leap;
+}
+
+function GetSundayInMonth(t, m, count){
+ var year = YearFromTime(t);
+ var tempDate;
+
+ if (count==='"first"') {
+ for (var d=1; d <= DaysInMonth(m, InLeapYear(t)); d++) {
+ tempDate = new Date(year, m, d);
+ if (tempDate.getDay()===0) {
+ return tempDate.valueOf();
+ }
+ }
+ } else if(count==='"last"') {
+ for (var d=DaysInMonth(m, InLeapYear(t)); d>0; d--) {
+ tempDate = new Date(year, m, d);
+ if (tempDate.getDay()===0) {
+ return tempDate.valueOf();
+ }
+ }
+ }
+ throw new Error("Unsupported 'count' arg:" + count);
+}
+/*
+function GetSundayInMonth(t, m, count){
+ var year = YearFromTime(t);
+ var leap = InLeapYear(t);
+ var day = 0;
+
+ if(m >= 1) day += DaysInMonth(0, leap);
+ if(m >= 2) day += DaysInMonth(1, leap);
+ if(m >= 3) day += DaysInMonth(2, leap);
+ if(m >= 4) day += DaysInMonth(3, leap);
+ if(m >= 5) day += DaysInMonth(4, leap);
+ if(m >= 6) day += DaysInMonth(5, leap);
+ if(m >= 7) day += DaysInMonth(6, leap);
+ if(m >= 8) day += DaysInMonth(7, leap);
+ if(m >= 9) day += DaysInMonth(8, leap);
+ if(m >= 10) day += DaysInMonth(9, leap);
+ if(m >= 11) day += DaysInMonth(10, leap);
+
+ var month_start = TimeFromYear(year)+day*msPerDay;
+ var sunday = 0;
+
+ if(count === "last"){
+ for(var last_sunday = month_start+DaysInMonth(m, leap)*msPerDay;
+ WeekDay(last_sunday)>0;
+ last_sunday -= msPerDay
+ ){};
+ sunday = last_sunday;
+ }
+ else {
+ for(var first_sunday = month_start;
+ WeekDay(first_sunday)>0;
+ first_sunday += msPerDay
+ ){};
+ sunday = first_sunday+7*msPerDay*(count-1);
+ }
+
+ return sunday;
+}*/
+
+function DaylightSavingTA(t) {
+// t = t-LocalTZA;
+
+ var DST_start = GetSundayInMonth(t, $DST_start_month, $DST_start_sunday) +
+ $DST_start_hour*msPerHour +
+ $DST_start_minutes*msPerMinute;
+
+ var k = new Date(DST_start);
+
+ var DST_end = GetSundayInMonth(t, $DST_end_month, $DST_end_sunday) +
+ $DST_end_hour*msPerHour +
+ $DST_end_minutes*msPerMinute;
+
+ if ( t >= DST_start && t < DST_end ) {
+ return msPerHour;
+ } else {
+ return 0;
+ }
+}
+
+//15.9.1.9 Local Time
+function LocalTime(t){
+ return t+LocalTZA+DaylightSavingTA(t);
+}
+
+function UTC(t) {
+ return t-LocalTZA-DaylightSavingTA(t-LocalTZA);
+}
+
+//15.9.1.10 Hours, Minutes, Second, and Milliseconds
+function HourFromTime(t){
+ return Math.floor(t/msPerHour)%HoursPerDay;
+}
+
+function MinFromTime(t){
+ return Math.floor(t/msPerMinute)%MinutesPerHour;
+}
+
+function SecFromTime(t){
+ return Math.floor(t/msPerSecond)%SecondsPerMinute;
+}
+
+function msFromTime(t){
+ return t%msPerSecond;
+}
+
+//15.9.1.11 MakeTime (hour, min, sec, ms)
+function MakeTime(hour, min, sec, ms){
+ if ( !isFinite(hour) || !isFinite(min) || !isFinite(sec) || !isFinite(ms)) {
+ return Number.NaN;
+ }
+
+ hour = ToInteger(hour);
+ min = ToInteger(min);
+ sec = ToInteger(sec);
+ ms = ToInteger(ms);
+
+ return ((hour*msPerHour) + (min*msPerMinute) + (sec*msPerSecond) + ms);
+}
+
+//15.9.1.12 MakeDay (year, month, date)
+function MakeDay(year, month, date) {
+ if ( !isFinite(year) || !isFinite(month) || !isFinite(date)) {
+ return Number.NaN;
+ }
+
+ year = ToInteger(year);
+ month = ToInteger(month);
+ date = ToInteger(date );
+
+ var result5 = year + Math.floor(month/12);
+ var result6 = month%12;
+
+ var sign = ( year < 1970 ) ? -1 : 1;
+ var t = ( year < 1970 ) ? 1 : 0;
+ var y = ( year < 1970 ) ? 1969 : 1970;
+
+ if( sign == -1 ){
+ for ( y = 1969; y >= year; y += sign ) {
+ t += sign * DaysInYear(y)*msPerDay;
+ }
+ } else {
+ for ( y = 1970 ; y < year; y += sign ) {
+ t += sign * DaysInYear(y)*msPerDay;
+ }
+ }
+
+ var leap = 0;
+ for ( var m = 0; m < month; m++ ) {
+ //if year is changed, than we need to recalculate leep
+ leap = InLeapYear(t);
+ t += DaysInMonth(m, leap)*msPerDay;
+ }
+
+ if ( YearFromTime(t) != result5 ) {
+ return Number.NaN;
+ }
+ if ( MonthFromTime(t) != result6 ) {
+ return Number.NaN;
+ }
+ if ( DateFromTime(t) != 1 ) {
+ return Number.NaN;
+ }
+
+ return Day(t)+date-1;
+}
+
+//15.9.1.13 MakeDate (day, time)
+function MakeDate( day, time ) {
+ if(!isFinite(day) || !isFinite(time)) {
+ return Number.NaN;
+ }
+
+ return day*msPerDay+time;
+}
+
+//15.9.1.14 TimeClip (time)
+function TimeClip(time) {
+ if(!isFinite(time) || Math.abs(time) > 8.64e15){
+ return Number.NaN;
+ }
+
+ return ToInteger(time);
+}
+
+//Test Functions
+//ConstructDate is considered deprecated, and should not be used directly from
+//test262 tests as it's incredibly sensitive to DST start/end dates that
+//vary with geographic location.
+function ConstructDate(year, month, date, hours, minutes, seconds, ms){
+ /*
+ * 1. Call ToNumber(year)
+ * 2. Call ToNumber(month)
+ * 3. If date is supplied use ToNumber(date); else use 1
+ * 4. If hours is supplied use ToNumber(hours); else use 0
+ * 5. If minutes is supplied use ToNumber(minutes); else use 0
+ * 6. If seconds is supplied use ToNumber(seconds); else use 0
+ * 7. If ms is supplied use ToNumber(ms); else use 0
+ * 8. If Result(1) is not NaN and 0 <= ToInteger(Result(1)) <= 99, Result(8) is
+ * 1900+ToInteger(Result(1)); otherwise, Result(8) is Result(1)
+ * 9. Compute MakeDay(Result(8), Result(2), Result(3))
+ * 10. Compute MakeTime(Result(4), Result(5), Result(6), Result(7))
+ * 11. Compute MakeDate(Result(9), Result(10))
+ * 12. Set the [[Value]] property of the newly constructed object to TimeClip(UTC(Result(11)))
+ */
+ var r1 = Number(year);
+ var r2 = Number(month);
+ var r3 = ((date && arguments.length > 2) ? Number(date) : 1);
+ var r4 = ((hours && arguments.length > 3) ? Number(hours) : 0);
+ var r5 = ((minutes && arguments.length > 4) ? Number(minutes) : 0);
+ var r6 = ((seconds && arguments.length > 5) ? Number(seconds) : 0);
+ var r7 = ((ms && arguments.length > 6) ? Number(ms) : 0);
+
+ var r8 = r1;
+
+ if(!isNaN(r1) && (0 <= ToInteger(r1)) && (ToInteger(r1) <= 99))
+ r8 = 1900+r1;
+
+ var r9 = MakeDay(r8, r2, r3);
+ var r10 = MakeTime(r4, r5, r6, r7);
+ var r11 = MakeDate(r9, r10);
+
+ var retVal = TimeClip(UTC(r11));
+ return retVal;
+}
+
+
+
+/**** Python code for initialize the above constants
+// We may want to replicate the following in JavaScript.
+// However, using JS date operations to generate parameters that are then used to
+// test those some date operations seems unsound. However, it isn't clear if there
+//is a good interoperable alternative.
+
+# Copyright 2009 the Sputnik authors. All rights reserved.
+# This code is governed by the BSD license found in the LICENSE file.
+
+def GetDaylightSavingsTimes():
+# Is the given floating-point time in DST?
+def IsDst(t):
+return time.localtime(t)[-1]
+# Binary search to find an interval between the two times no greater than
+# delta where DST switches, returning the midpoint.
+def FindBetween(start, end, delta):
+while end - start > delta:
+middle = (end + start) / 2
+if IsDst(middle) == IsDst(start):
+start = middle
+else:
+end = middle
+return (start + end) / 2
+now = time.time()
+one_month = (30 * 24 * 60 * 60)
+# First find a date with different daylight savings. To avoid corner cases
+# we try four months before and after today.
+after = now + 4 * one_month
+before = now - 4 * one_month
+if IsDst(now) == IsDst(before) and IsDst(now) == IsDst(after):
+logger.warning("Was unable to determine DST info.")
+return None
+# Determine when the change occurs between now and the date we just found
+# in a different DST.
+if IsDst(now) != IsDst(before):
+first = FindBetween(before, now, 1)
+else:
+first = FindBetween(now, after, 1)
+# Determine when the change occurs between three and nine months from the
+# first.
+second = FindBetween(first + 3 * one_month, first + 9 * one_month, 1)
+# Find out which switch is into and which if out of DST
+if IsDst(first - 1) and not IsDst(first + 1):
+start = second
+end = first
+else:
+start = first
+end = second
+return (start, end)
+
+
+def GetDaylightSavingsAttribs():
+times = GetDaylightSavingsTimes()
+if not times:
+return None
+(start, end) = times
+def DstMonth(t):
+return time.localtime(t)[1] - 1
+def DstHour(t):
+return time.localtime(t - 1)[3] + 1
+def DstSunday(t):
+if time.localtime(t)[2] > 15:
+return "'last'"
+else:
+return "'first'"
+def DstMinutes(t):
+return (time.localtime(t - 1)[4] + 1) % 60
+attribs = { }
+attribs['start_month'] = DstMonth(start)
+attribs['end_month'] = DstMonth(end)
+attribs['start_sunday'] = DstSunday(start)
+attribs['end_sunday'] = DstSunday(end)
+attribs['start_hour'] = DstHour(start)
+attribs['end_hour'] = DstHour(end)
+attribs['start_minutes'] = DstMinutes(start)
+attribs['end_minutes'] = DstMinutes(end)
+return attribs
+
+*********/
+
+//--Test case registration-----------------------------------------------------
+function runTestCase(testcase) {
+ if (testcase() !== true) {
+ $ERROR("Test case returned non-true value!");
+ }
+}
diff --git a/js/src/tests/supporting/test262-browser.js b/js/src/tests/supporting/test262-browser.js
new file mode 100644
index 000000000..fb4c18106
--- /dev/null
+++ b/js/src/tests/supporting/test262-browser.js
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test262 function $INCLUDE loads a file with support functions for the tests.
+ * Our initial import strategy will be to attempt to load all these files
+ * unconditionally (this may change at some point), so just ignore the call.
+ * This function replaces one in shell.js.
+ */
+function $INCLUDE(file) {}
diff --git a/js/src/tests/supporting/test262-shell.js b/js/src/tests/supporting/test262-shell.js
new file mode 100644
index 000000000..4f1af7fb5
--- /dev/null
+++ b/js/src/tests/supporting/test262-shell.js
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * The current crop of Test262 test cases that we run are expected to pass
+ * unless they crash or throw. (This isn't true for all Test262 test cases --
+ * for the ones marked @negative the logic is inverted. We'll have to deal with
+ * that concern eventually, but for now we're punting so we can run subsets of
+ * Test262 tests.)
+ */
+testPassesUnlessItThrows();
+
+/*
+ * Test262 function $ERROR throws an error with the message provided. Test262
+ * test cases call it to indicate failure.
+ */
+function $ERROR(msg)
+{
+ throw new Error("Test262 error: " + msg);
+}
+
+/*
+ * Test262 function $INCLUDE loads a file with support functions for the tests.
+ * This function is replaced in browser.js.
+ */
+function $INCLUDE(file)
+{
+ load("supporting/" + file);
+}
+
+/*
+ * Test262 function fnGlobalObject returns the global object.
+ */
+var fnGlobalObject = (function()
+{
+ var global = Function("return this")();
+ return function fnGlobalObject() { return global; };
+})();
diff --git a/js/src/tests/supporting/test402-browser.js b/js/src/tests/supporting/test402-browser.js
new file mode 100644
index 000000000..132215374
--- /dev/null
+++ b/js/src/tests/supporting/test402-browser.js
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Undo at least the damage done by taintArray so that the jstests
+ * harness won't die. The properties added to Object.prototype by the various
+ * tests have names that are less likely to cause trouble.
+ */
+setRestoreFunction((function () {
+ var Array_indexOf = Array.prototype.indexOf;
+ var Array_join = Array.prototype.join;
+ var Array_push = Array.prototype.push;
+ var Array_slice = Array.prototype.slice;
+ var Array_sort = Array.prototype.sort;
+ return function () {
+ delete Array.prototype["0"];
+ Array.prototype.indexOf = Array_indexOf;
+ Array.prototype.join = Array_join;
+ Array.prototype.push = Array_push;
+ Array.prototype.slice = Array_slice;
+ Array.prototype.sort = Array_sort;
+ };
+}()));
diff --git a/js/src/tests/supporting/test402-shell.js b/js/src/tests/supporting/test402-shell.js
new file mode 100644
index 000000000..2e6826e91
--- /dev/null
+++ b/js/src/tests/supporting/test402-shell.js
@@ -0,0 +1,10 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test402 tests all pass unless they throw, and there are no @negative tests.
+ * Once Test262 includes @negative support, and this call in test262-shell.js is
+ * removed, this'll need to be uncommented.
+ */
+//testPassesUnlessItThrows();
diff --git a/js/src/tests/supporting/testBuiltInObject.js b/js/src/tests/supporting/testBuiltInObject.js
new file mode 100644
index 000000000..3a8d24fdc
--- /dev/null
+++ b/js/src/tests/supporting/testBuiltInObject.js
@@ -0,0 +1,124 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/**
+ * @description Tests that obj meets the requirements for built-in objects
+ * defined by the introduction of chapter 15 of the ECMAScript Language Specification.
+ * @param {Object} obj the object to be tested.
+ * @param {boolean} isFunction whether the specification describes obj as a function.
+ * @param {boolean} isConstructor whether the specification describes obj as a constructor.
+ * @param {String[]} properties an array with the names of the built-in properties of obj,
+ * excluding length, prototype, or properties with non-default attributes.
+ * @param {number} length for functions only: the length specified for the function
+ * or derived from the argument list.
+ * @author Norbert Lindenberg
+ */
+
+function testBuiltInObject(obj, isFunction, isConstructor, properties, length) {
+
+ if (obj === undefined) {
+ $ERROR("Object being tested is undefined.");
+ }
+
+ var objString = Object.prototype.toString.call(obj);
+ if (isFunction) {
+ if (objString !== "[object Function]") {
+ $ERROR("The [[Class]] internal property of a built-in function must be " +
+ "\"Function\", but toString() returns " + objString);
+ }
+ } else {
+ if (objString !== "[object Object]") {
+ $ERROR("The [[Class]] internal property of a built-in non-function object must be " +
+ "\"Object\", but toString() returns " + objString);
+ }
+ }
+
+ if (!Object.isExtensible(obj)) {
+ $ERROR("Built-in objects must be extensible.");
+ }
+
+ if (isFunction && Object.getPrototypeOf(obj) !== Function.prototype) {
+ $ERROR("Built-in functions must have Function.prototype as their prototype.");
+ }
+
+ if (isConstructor && Object.getPrototypeOf(obj.prototype) !== Object.prototype) {
+ $ERROR("Built-in prototype objects must have Object.prototype as their prototype.");
+ }
+
+ // verification of the absence of the [[Construct]] internal property has
+ // been moved to the end of the test
+
+ // verification of the absence of the prototype property has
+ // been moved to the end of the test
+
+ if (isFunction) {
+
+ if (typeof obj.length !== "number" || obj.length !== Math.floor(obj.length)) {
+ $ERROR("Built-in functions must have a length property with an integer value.");
+ }
+
+ if (obj.length !== length) {
+ $ERROR("Function's length property doesn't have specified value; expected " +
+ length + ", got " + obj.length + ".");
+ }
+
+ var desc = Object.getOwnPropertyDescriptor(obj, "length");
+ if (desc.writable) {
+ $ERROR("The length property of a built-in function must not be writable.");
+ }
+ if (desc.enumerable) {
+ $ERROR("The length property of a built-in function must not be enumerable.");
+ }
+ if (desc.configurable) {
+ $ERROR("The length property of a built-in function must not be configurable.");
+ }
+ }
+
+ properties.forEach(function(prop) {
+ var desc = Object.getOwnPropertyDescriptor(obj, prop);
+ if (desc === undefined) {
+ $ERROR("Missing property " + prop + ".");
+ }
+ // accessor properties don't have writable attribute
+ if (desc.hasOwnProperty("writable") && !desc.writable) {
+ $ERROR("The " + prop + " property of this built-in function must be writable.");
+ }
+ if (desc.enumerable) {
+ $ERROR("The " + prop + " property of this built-in function must not be enumerable.");
+ }
+ if (!desc.configurable) {
+ $ERROR("The " + prop + " property of this built-in function must be configurable.");
+ }
+ });
+
+ // The remaining sections have been moved to the end of the test because
+ // unbound non-constructor functions written in JavaScript cannot possibly
+ // pass them, and we still want to test JavaScript implementations as much
+ // as possible.
+
+ var exception;
+ if (isFunction && !isConstructor) {
+ // this is not a complete test for the presence of [[Construct]]:
+ // if it's absent, the exception must be thrown, but it may also
+ // be thrown if it's present and just has preconditions related to
+ // arguments or the this value that this statement doesn't meet.
+ try {
+ /*jshint newcap:false*/
+ var instance = new obj();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception === undefined || exception.name !== "TypeError") {
+ $ERROR("Built-in functions that aren't constructors must throw TypeError when " +
+ "used in a \"new\" statement.");
+ }
+ }
+
+ if (isFunction && !isConstructor && obj.hasOwnProperty("prototype")) {
+ $ERROR("Built-in functions that aren't constructors must not have a prototype property.");
+ }
+
+ // passed the complete test!
+ return true;
+}
+
diff --git a/js/src/tests/supporting/testIntl.js b/js/src/tests/supporting/testIntl.js
new file mode 100644
index 000000000..b009a2e9e
--- /dev/null
+++ b/js/src/tests/supporting/testIntl.js
@@ -0,0 +1,1167 @@
+// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
+// Copyright 2012-2013 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/**
+ * This file contains shared functions for the tests in the conformance test
+ * suite for the ECMAScript Internationalization API.
+ * @author Norbert Lindenberg
+ */
+
+
+/**
+ * @description Calls the provided function for every service constructor in
+ * the Intl object, until f returns a falsy value. It returns the result of the
+ * last call to f, mapped to a boolean.
+ * @param {Function} f the function to call for each service constructor in
+ * the Intl object.
+ * @param {Function} Constructor the constructor object to test with.
+ * @result {Boolean} whether the test succeeded.
+ */
+function testWithIntlConstructors(f) {
+ var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
+ return constructors.every(function (constructor) {
+ var Constructor = Intl[constructor];
+ var result;
+ try {
+ result = f(Constructor);
+ } catch (e) {
+ e.message += " (Testing with " + constructor + ".)";
+ throw e;
+ }
+ return result;
+ });
+}
+
+
+/**
+ * Returns the name of the given constructor object, which must be one of
+ * Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
+ * @param {object} Constructor a constructor
+ * @return {string} the name of the constructor
+ */
+function getConstructorName(Constructor) {
+ switch (Constructor) {
+ case Intl.Collator:
+ return "Collator";
+ case Intl.NumberFormat:
+ return "NumberFormat";
+ case Intl.DateTimeFormat:
+ return "DateTimeFormat";
+ default:
+ $ERROR("test internal error: unknown Constructor");
+ }
+}
+
+
+/**
+ * Taints a named data property of the given object by installing
+ * a setter that throws an exception.
+ * @param {object} obj the object whose data property to taint
+ * @param {string} property the property to taint
+ */
+function taintDataProperty(obj, property) {
+ Object.defineProperty(obj, property, {
+ set: function(value) {
+ $ERROR("Client code can adversely affect behavior: setter for " + property + ".");
+ },
+ enumerable: false,
+ configurable: true
+ });
+}
+
+
+/**
+ * Taints a named method of the given object by replacing it with a function
+ * that throws an exception.
+ * @param {object} obj the object whose method to taint
+ * @param {string} property the name of the method to taint
+ */
+function taintMethod(obj, property) {
+ Object.defineProperty(obj, property, {
+ value: function() {
+ $ERROR("Client code can adversely affect behavior: method " + property + ".");
+ },
+ writable: true,
+ enumerable: false,
+ configurable: true
+ });
+}
+
+
+/**
+ * Taints the given properties (and similarly named properties) by installing
+ * setters on Object.prototype that throw exceptions.
+ * @param {Array} properties an array of property names to taint
+ */
+function taintProperties(properties) {
+ properties.forEach(function (property) {
+ var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
+ adaptedProperties.forEach(function (property) {
+ taintDataProperty(Object.prototype, property);
+ });
+ });
+}
+
+
+/**
+ * Taints the Array object by creating a setter for the property "0" and
+ * replacing some key methods with functions that throw exceptions.
+ */
+function taintArray() {
+ taintDataProperty(Array.prototype, "0");
+ taintMethod(Array.prototype, "indexOf");
+ taintMethod(Array.prototype, "join");
+ taintMethod(Array.prototype, "push");
+ taintMethod(Array.prototype, "slice");
+ taintMethod(Array.prototype, "sort");
+}
+
+
+// auxiliary data for getLocaleSupportInfo
+var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
+var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
+var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
+var localeSupportInfo = {};
+
+
+/**
+ * Gets locale support info for the given constructor object, which must be one
+ * of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
+ * @param {object} Constructor the constructor for which to get locale support info
+ * @return {object} locale support info with the following properties:
+ * supported: array of fully supported language tags
+ * byFallback: array of language tags that are supported through fallbacks
+ * unsupported: array of unsupported language tags
+ */
+function getLocaleSupportInfo(Constructor) {
+ var constructorName = getConstructorName(Constructor);
+ if (localeSupportInfo[constructorName] !== undefined) {
+ return localeSupportInfo[constructorName];
+ }
+
+ var allTags = [];
+ var i, j, k;
+ var language, script, country;
+ for (i = 0; i < languages.length; i++) {
+ language = languages[i];
+ allTags.push(language);
+ for (j = 0; j < scripts.length; j++) {
+ script = scripts[j];
+ allTags.push(language + "-" + script);
+ for (k = 0; k < countries.length; k++) {
+ country = countries[k];
+ allTags.push(language + "-" + script + "-" + country);
+ }
+ }
+ for (k = 0; k < countries.length; k++) {
+ country = countries[k];
+ allTags.push(language + "-" + country);
+ }
+ }
+
+ var supported = [];
+ var byFallback = [];
+ var unsupported = [];
+ for (i = 0; i < allTags.length; i++) {
+ var request = allTags[i];
+ var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
+ if (request === result) {
+ supported.push(request);
+ } else if (request.indexOf(result) === 0) {
+ byFallback.push(request);
+ } else {
+ unsupported.push(request);
+ }
+ }
+
+ localeSupportInfo[constructorName] = {
+ supported: supported,
+ byFallback: byFallback,
+ unsupported: unsupported
+ };
+
+ return localeSupportInfo[constructorName];
+}
+
+
+/**
+ * @description Tests whether locale is a String value representing a
+ * structurally valid and canonicalized BCP 47 language tag, as defined in
+ * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
+ * Specification.
+ * @param {String} locale the string to be tested.
+ * @result {Boolean} whether the test succeeded.
+ */
+function isCanonicalizedStructurallyValidLanguageTag(locale) {
+
+ /**
+ * Regular expression defining BCP 47 language tags.
+ *
+ * Spec: RFC 5646 section 2.1.
+ */
+ var alpha = "[a-zA-Z]",
+ digit = "[0-9]",
+ alphanum = "(" + alpha + "|" + digit + ")",
+ regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
+ 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)",
+ grandfathered = "(" + irregular + "|" + regular + ")",
+ privateuse = "(x(-[a-z0-9]{1,8})+)",
+ singleton = "(" + digit + "|[A-WY-Za-wy-z])",
+ extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
+ variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
+ region = "(" + alpha + "{2}|" + digit + "{3})",
+ script = "(" + alpha + "{4})",
+ extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
+ language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
+ langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
+ languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
+ languageTagRE = new RegExp(languageTag, "i");
+ var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
+ duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
+ duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
+ duplicateVariantRE = new RegExp(duplicateVariant, "i");
+
+
+ /**
+ * Verifies that the given string is a well-formed BCP 47 language tag
+ * with no duplicate variant or singleton subtags.
+ *
+ * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
+ */
+ function isStructurallyValidLanguageTag(locale) {
+ if (!languageTagRE.test(locale)) {
+ return false;
+ }
+ locale = locale.split(/-x-/)[0];
+ return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
+ }
+
+
+ /**
+ * Mappings from complete tags to preferred values.
+ *
+ * Spec: IANA Language Subtag Registry.
+ */
+ var __tagMappings = {
+ // property names must be in lower case; values in canonical form
+
+ // grandfathered tags from IANA language subtag registry, file date 2011-08-25
+ "art-lojban": "jbo",
+ "cel-gaulish": "cel-gaulish",
+ "en-gb-oed": "en-GB-oed",
+ "i-ami": "ami",
+ "i-bnn": "bnn",
+ "i-default": "i-default",
+ "i-enochian": "i-enochian",
+ "i-hak": "hak",
+ "i-klingon": "tlh",
+ "i-lux": "lb",
+ "i-mingo": "i-mingo",
+ "i-navajo": "nv",
+ "i-pwn": "pwn",
+ "i-tao": "tao",
+ "i-tay": "tay",
+ "i-tsu": "tsu",
+ "no-bok": "nb",
+ "no-nyn": "nn",
+ "sgn-be-fr": "sfb",
+ "sgn-be-nl": "vgt",
+ "sgn-ch-de": "sgg",
+ "zh-guoyu": "cmn",
+ "zh-hakka": "hak",
+ "zh-min": "zh-min",
+ "zh-min-nan": "nan",
+ "zh-xiang": "hsn",
+ // deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
+ "sgn-br": "bzs",
+ "sgn-co": "csn",
+ "sgn-de": "gsg",
+ "sgn-dk": "dsl",
+ "sgn-es": "ssp",
+ "sgn-fr": "fsl",
+ "sgn-gb": "bfi",
+ "sgn-gr": "gss",
+ "sgn-ie": "isg",
+ "sgn-it": "ise",
+ "sgn-jp": "jsl",
+ "sgn-mx": "mfs",
+ "sgn-ni": "ncs",
+ "sgn-nl": "dse",
+ "sgn-no": "nsl",
+ "sgn-pt": "psr",
+ "sgn-se": "swl",
+ "sgn-us": "ase",
+ "sgn-za": "sfs",
+ "zh-cmn": "cmn",
+ "zh-cmn-hans": "cmn-Hans",
+ "zh-cmn-hant": "cmn-Hant",
+ "zh-gan": "gan",
+ "zh-wuu": "wuu",
+ "zh-yue": "yue",
+ // deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
+ "ja-latn-hepburn-heploc": "ja-Latn-alalc97"
+ };
+
+
+ /**
+ * Mappings from non-extlang subtags to preferred values.
+ *
+ * Spec: IANA Language Subtag Registry.
+ */
+ var __subtagMappings = {
+ // property names and values must be in canonical case
+ // language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
+ "in": "id",
+ "iw": "he",
+ "ji": "yi",
+ "jw": "jv",
+ "mo": "ro",
+ "ayx": "nun",
+ "cjr": "mom",
+ "cmk": "xch",
+ "drh": "khk",
+ "drw": "prs",
+ "gav": "dev",
+ "mst": "mry",
+ "myt": "mry",
+ "tie": "ras",
+ "tkk": "twm",
+ "tnf": "prs",
+ // region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
+ "BU": "MM",
+ "DD": "DE",
+ "FX": "FR",
+ "TP": "TL",
+ "YD": "YE",
+ "ZR": "CD"
+ };
+
+
+ /**
+ * Mappings from extlang subtags to preferred values.
+ *
+ * Spec: IANA Language Subtag Registry.
+ */
+ var __extlangMappings = {
+ // extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
+ // values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
+ "aao": ["aao", "ar"],
+ "abh": ["abh", "ar"],
+ "abv": ["abv", "ar"],
+ "acm": ["acm", "ar"],
+ "acq": ["acq", "ar"],
+ "acw": ["acw", "ar"],
+ "acx": ["acx", "ar"],
+ "acy": ["acy", "ar"],
+ "adf": ["adf", "ar"],
+ "ads": ["ads", "sgn"],
+ "aeb": ["aeb", "ar"],
+ "aec": ["aec", "ar"],
+ "aed": ["aed", "sgn"],
+ "aen": ["aen", "sgn"],
+ "afb": ["afb", "ar"],
+ "afg": ["afg", "sgn"],
+ "ajp": ["ajp", "ar"],
+ "apc": ["apc", "ar"],
+ "apd": ["apd", "ar"],
+ "arb": ["arb", "ar"],
+ "arq": ["arq", "ar"],
+ "ars": ["ars", "ar"],
+ "ary": ["ary", "ar"],
+ "arz": ["arz", "ar"],
+ "ase": ["ase", "sgn"],
+ "asf": ["asf", "sgn"],
+ "asp": ["asp", "sgn"],
+ "asq": ["asq", "sgn"],
+ "asw": ["asw", "sgn"],
+ "auz": ["auz", "ar"],
+ "avl": ["avl", "ar"],
+ "ayh": ["ayh", "ar"],
+ "ayl": ["ayl", "ar"],
+ "ayn": ["ayn", "ar"],
+ "ayp": ["ayp", "ar"],
+ "bbz": ["bbz", "ar"],
+ "bfi": ["bfi", "sgn"],
+ "bfk": ["bfk", "sgn"],
+ "bjn": ["bjn", "ms"],
+ "bog": ["bog", "sgn"],
+ "bqn": ["bqn", "sgn"],
+ "bqy": ["bqy", "sgn"],
+ "btj": ["btj", "ms"],
+ "bve": ["bve", "ms"],
+ "bvl": ["bvl", "sgn"],
+ "bvu": ["bvu", "ms"],
+ "bzs": ["bzs", "sgn"],
+ "cdo": ["cdo", "zh"],
+ "cds": ["cds", "sgn"],
+ "cjy": ["cjy", "zh"],
+ "cmn": ["cmn", "zh"],
+ "coa": ["coa", "ms"],
+ "cpx": ["cpx", "zh"],
+ "csc": ["csc", "sgn"],
+ "csd": ["csd", "sgn"],
+ "cse": ["cse", "sgn"],
+ "csf": ["csf", "sgn"],
+ "csg": ["csg", "sgn"],
+ "csl": ["csl", "sgn"],
+ "csn": ["csn", "sgn"],
+ "csq": ["csq", "sgn"],
+ "csr": ["csr", "sgn"],
+ "czh": ["czh", "zh"],
+ "czo": ["czo", "zh"],
+ "doq": ["doq", "sgn"],
+ "dse": ["dse", "sgn"],
+ "dsl": ["dsl", "sgn"],
+ "dup": ["dup", "ms"],
+ "ecs": ["ecs", "sgn"],
+ "esl": ["esl", "sgn"],
+ "esn": ["esn", "sgn"],
+ "eso": ["eso", "sgn"],
+ "eth": ["eth", "sgn"],
+ "fcs": ["fcs", "sgn"],
+ "fse": ["fse", "sgn"],
+ "fsl": ["fsl", "sgn"],
+ "fss": ["fss", "sgn"],
+ "gan": ["gan", "zh"],
+ "gom": ["gom", "kok"],
+ "gse": ["gse", "sgn"],
+ "gsg": ["gsg", "sgn"],
+ "gsm": ["gsm", "sgn"],
+ "gss": ["gss", "sgn"],
+ "gus": ["gus", "sgn"],
+ "hab": ["hab", "sgn"],
+ "haf": ["haf", "sgn"],
+ "hak": ["hak", "zh"],
+ "hds": ["hds", "sgn"],
+ "hji": ["hji", "ms"],
+ "hks": ["hks", "sgn"],
+ "hos": ["hos", "sgn"],
+ "hps": ["hps", "sgn"],
+ "hsh": ["hsh", "sgn"],
+ "hsl": ["hsl", "sgn"],
+ "hsn": ["hsn", "zh"],
+ "icl": ["icl", "sgn"],
+ "ils": ["ils", "sgn"],
+ "inl": ["inl", "sgn"],
+ "ins": ["ins", "sgn"],
+ "ise": ["ise", "sgn"],
+ "isg": ["isg", "sgn"],
+ "isr": ["isr", "sgn"],
+ "jak": ["jak", "ms"],
+ "jax": ["jax", "ms"],
+ "jcs": ["jcs", "sgn"],
+ "jhs": ["jhs", "sgn"],
+ "jls": ["jls", "sgn"],
+ "jos": ["jos", "sgn"],
+ "jsl": ["jsl", "sgn"],
+ "jus": ["jus", "sgn"],
+ "kgi": ["kgi", "sgn"],
+ "knn": ["knn", "kok"],
+ "kvb": ["kvb", "ms"],
+ "kvk": ["kvk", "sgn"],
+ "kvr": ["kvr", "ms"],
+ "kxd": ["kxd", "ms"],
+ "lbs": ["lbs", "sgn"],
+ "lce": ["lce", "ms"],
+ "lcf": ["lcf", "ms"],
+ "liw": ["liw", "ms"],
+ "lls": ["lls", "sgn"],
+ "lsg": ["lsg", "sgn"],
+ "lsl": ["lsl", "sgn"],
+ "lso": ["lso", "sgn"],
+ "lsp": ["lsp", "sgn"],
+ "lst": ["lst", "sgn"],
+ "lsy": ["lsy", "sgn"],
+ "ltg": ["ltg", "lv"],
+ "lvs": ["lvs", "lv"],
+ "lzh": ["lzh", "zh"],
+ "max": ["max", "ms"],
+ "mdl": ["mdl", "sgn"],
+ "meo": ["meo", "ms"],
+ "mfa": ["mfa", "ms"],
+ "mfb": ["mfb", "ms"],
+ "mfs": ["mfs", "sgn"],
+ "min": ["min", "ms"],
+ "mnp": ["mnp", "zh"],
+ "mqg": ["mqg", "ms"],
+ "mre": ["mre", "sgn"],
+ "msd": ["msd", "sgn"],
+ "msi": ["msi", "ms"],
+ "msr": ["msr", "sgn"],
+ "mui": ["mui", "ms"],
+ "mzc": ["mzc", "sgn"],
+ "mzg": ["mzg", "sgn"],
+ "mzy": ["mzy", "sgn"],
+ "nan": ["nan", "zh"],
+ "nbs": ["nbs", "sgn"],
+ "ncs": ["ncs", "sgn"],
+ "nsi": ["nsi", "sgn"],
+ "nsl": ["nsl", "sgn"],
+ "nsp": ["nsp", "sgn"],
+ "nsr": ["nsr", "sgn"],
+ "nzs": ["nzs", "sgn"],
+ "okl": ["okl", "sgn"],
+ "orn": ["orn", "ms"],
+ "ors": ["ors", "ms"],
+ "pel": ["pel", "ms"],
+ "pga": ["pga", "ar"],
+ "pks": ["pks", "sgn"],
+ "prl": ["prl", "sgn"],
+ "prz": ["prz", "sgn"],
+ "psc": ["psc", "sgn"],
+ "psd": ["psd", "sgn"],
+ "pse": ["pse", "ms"],
+ "psg": ["psg", "sgn"],
+ "psl": ["psl", "sgn"],
+ "pso": ["pso", "sgn"],
+ "psp": ["psp", "sgn"],
+ "psr": ["psr", "sgn"],
+ "pys": ["pys", "sgn"],
+ "rms": ["rms", "sgn"],
+ "rsi": ["rsi", "sgn"],
+ "rsl": ["rsl", "sgn"],
+ "sdl": ["sdl", "sgn"],
+ "sfb": ["sfb", "sgn"],
+ "sfs": ["sfs", "sgn"],
+ "sgg": ["sgg", "sgn"],
+ "sgx": ["sgx", "sgn"],
+ "shu": ["shu", "ar"],
+ "slf": ["slf", "sgn"],
+ "sls": ["sls", "sgn"],
+ "sqs": ["sqs", "sgn"],
+ "ssh": ["ssh", "ar"],
+ "ssp": ["ssp", "sgn"],
+ "ssr": ["ssr", "sgn"],
+ "svk": ["svk", "sgn"],
+ "swc": ["swc", "sw"],
+ "swh": ["swh", "sw"],
+ "swl": ["swl", "sgn"],
+ "syy": ["syy", "sgn"],
+ "tmw": ["tmw", "ms"],
+ "tse": ["tse", "sgn"],
+ "tsm": ["tsm", "sgn"],
+ "tsq": ["tsq", "sgn"],
+ "tss": ["tss", "sgn"],
+ "tsy": ["tsy", "sgn"],
+ "tza": ["tza", "sgn"],
+ "ugn": ["ugn", "sgn"],
+ "ugy": ["ugy", "sgn"],
+ "ukl": ["ukl", "sgn"],
+ "uks": ["uks", "sgn"],
+ "urk": ["urk", "ms"],
+ "uzn": ["uzn", "uz"],
+ "uzs": ["uzs", "uz"],
+ "vgt": ["vgt", "sgn"],
+ "vkk": ["vkk", "ms"],
+ "vkt": ["vkt", "ms"],
+ "vsi": ["vsi", "sgn"],
+ "vsl": ["vsl", "sgn"],
+ "vsv": ["vsv", "sgn"],
+ "wuu": ["wuu", "zh"],
+ "xki": ["xki", "sgn"],
+ "xml": ["xml", "sgn"],
+ "xmm": ["xmm", "ms"],
+ "xms": ["xms", "sgn"],
+ "yds": ["yds", "sgn"],
+ "ysl": ["ysl", "sgn"],
+ "yue": ["yue", "zh"],
+ "zib": ["zib", "sgn"],
+ "zlm": ["zlm", "ms"],
+ "zmi": ["zmi", "ms"],
+ "zsl": ["zsl", "sgn"],
+ "zsm": ["zsm", "ms"]
+ };
+
+
+ /**
+ * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
+ *
+ * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
+ * Spec: RFC 5646, section 4.5.
+ */
+ function canonicalizeLanguageTag(locale) {
+
+ // start with lower case for easier processing, and because most subtags will need to be lower case anyway
+ locale = locale.toLowerCase();
+
+ // handle mappings for complete tags
+ if (__tagMappings.hasOwnProperty(locale)) {
+ return __tagMappings[locale];
+ }
+
+ var subtags = locale.split("-");
+ var i = 0;
+
+ // handle standard part: all subtags before first singleton or "x"
+ while (i < subtags.length) {
+ var subtag = subtags[i];
+ if (subtag.length === 1 && (i > 0 || subtag === "x")) {
+ break;
+ } else if (i !== 0 && subtag.length === 2) {
+ subtag = subtag.toUpperCase();
+ } else if (subtag.length === 4) {
+ subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
+ }
+ if (__subtagMappings.hasOwnProperty(subtag)) {
+ subtag = __subtagMappings[subtag];
+ } else if (__extlangMappings.hasOwnProperty(subtag)) {
+ subtag = __extlangMappings[subtag][0];
+ if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
+ subtags.shift();
+ i--;
+ }
+ }
+ subtags[i] = subtag;
+ i++;
+ }
+ var normal = subtags.slice(0, i).join("-");
+
+ // handle extensions
+ var extensions = [];
+ while (i < subtags.length && subtags[i] !== "x") {
+ var extensionStart = i;
+ i++;
+ while (i < subtags.length && subtags[i].length > 1) {
+ i++;
+ }
+ var extension = subtags.slice(extensionStart, i).join("-");
+ extensions.push(extension);
+ }
+ extensions.sort();
+
+ // handle private use
+ var privateUse;
+ if (i < subtags.length) {
+ privateUse = subtags.slice(i).join("-");
+ }
+
+ // put everything back together
+ var canonical = normal;
+ if (extensions.length > 0) {
+ canonical += "-" + extensions.join("-");
+ }
+ if (privateUse !== undefined) {
+ if (canonical.length > 0) {
+ canonical += "-" + privateUse;
+ } else {
+ canonical = privateUse;
+ }
+ }
+
+ return canonical;
+ }
+
+ return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
+ canonicalizeLanguageTag(locale) === locale;
+}
+
+
+/**
+ * Tests whether the named options property is correctly handled by the given constructor.
+ * @param {object} Constructor the constructor to test.
+ * @param {string} property the name of the options property to test.
+ * @param {string} type the type that values of the property are expected to have
+ * @param {Array} [values] an array of allowed values for the property. Not needed for boolean.
+ * @param {any} fallback the fallback value that the property assumes if not provided.
+ * @param {object} testOptions additional options:
+ * @param {boolean} isOptional whether support for this property is optional for implementations.
+ * @param {boolean} noReturn whether the resulting value of the property is not returned.
+ * @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent.
+ * @param {object} extra additional option to pass along, properties are value -> {option: value}.
+ * @return {boolean} whether the test succeeded.
+ */
+function testOption(Constructor, property, type, values, fallback, testOptions) {
+ var isOptional = testOptions !== undefined && testOptions.isOptional === true;
+ var noReturn = testOptions !== undefined && testOptions.noReturn === true;
+ var isILD = testOptions !== undefined && testOptions.isILD === true;
+
+ function addExtraOptions(options, value, testOptions) {
+ if (testOptions !== undefined && testOptions.extra !== undefined) {
+ var extra;
+ if (value !== undefined && testOptions.extra[value] !== undefined) {
+ extra = testOptions.extra[value];
+ } else if (testOptions.extra.any !== undefined) {
+ extra = testOptions.extra.any;
+ }
+ if (extra !== undefined) {
+ Object.getOwnPropertyNames(extra).forEach(function (prop) {
+ options[prop] = extra[prop];
+ });
+ }
+ }
+ }
+
+ var testValues, options, obj, expected, actual, error;
+
+ // test that the specified values are accepted. Also add values that convert to specified values.
+ if (type === "boolean") {
+ if (values === undefined) {
+ values = [true, false];
+ }
+ testValues = values.slice(0);
+ testValues.push(888);
+ testValues.push(0);
+ } else if (type === "string") {
+ testValues = values.slice(0);
+ testValues.push({toString: function () { return values[0]; }});
+ }
+ testValues.forEach(function (value) {
+ options = {};
+ options[property] = value;
+ addExtraOptions(options, value, testOptions);
+ obj = new Constructor(undefined, options);
+ if (noReturn) {
+ if (obj.resolvedOptions().hasOwnProperty(property)) {
+ $ERROR("Option property " + property + " is returned, but shouldn't be.");
+ }
+ } else {
+ actual = obj.resolvedOptions()[property];
+ if (isILD) {
+ if (actual !== undefined && values.indexOf(actual) === -1) {
+ $ERROR("Invalid value " + actual + " returned for property " + property + ".");
+ }
+ } else {
+ if (type === "boolean") {
+ expected = Boolean(value);
+ } else if (type === "string") {
+ expected = String(value);
+ }
+ if (actual !== expected && !(isOptional && actual === undefined)) {
+ $ERROR("Option value " + value + " for property " + property +
+ " was not accepted; got " + actual + " instead.");
+ }
+ }
+ }
+ });
+
+ // test that invalid values are rejected
+ if (type === "string") {
+ var invalidValues = ["invalidValue", -1, null];
+ // assume that we won't have values in caseless scripts
+ if (values[0].toUpperCase() !== values[0]) {
+ invalidValues.push(values[0].toUpperCase());
+ } else {
+ invalidValues.push(values[0].toLowerCase());
+ }
+ invalidValues.forEach(function (value) {
+ options = {};
+ options[property] = value;
+ addExtraOptions(options, value, testOptions);
+ error = undefined;
+ try {
+ obj = new Constructor(undefined, options);
+ } catch (e) {
+ error = e;
+ }
+ if (error === undefined) {
+ $ERROR("Invalid option value " + value + " for property " + property + " was not rejected.");
+ } else if (error.name !== "RangeError") {
+ $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + ".");
+ }
+ });
+ }
+
+ // test that fallback value or another valid value is used if no options value is provided
+ if (!noReturn) {
+ options = {};
+ addExtraOptions(options, undefined, testOptions);
+ obj = new Constructor(undefined, options);
+ actual = obj.resolvedOptions()[property];
+ if (!(isOptional && actual === undefined)) {
+ if (fallback !== undefined) {
+ if (actual !== fallback) {
+ $ERROR("Option fallback value " + fallback + " for property " + property +
+ " was not used; got " + actual + " instead.");
+ }
+ } else {
+ if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) {
+ $ERROR("Invalid value " + actual + " returned for property " + property + ".");
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Tests whether the named property of the given object has a valid value
+ * and the default attributes of the properties of an object literal.
+ * @param {Object} obj the object to be tested.
+ * @param {string} property the name of the property
+ * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
+ * an array of valid values.
+ * @exception if the property has an invalid value.
+ */
+function testProperty(obj, property, valid) {
+ var desc = Object.getOwnPropertyDescriptor(obj, property);
+ if (!desc.writable) {
+ $ERROR("Property " + property + " must be writable.");
+ }
+ if (!desc.enumerable) {
+ $ERROR("Property " + property + " must be enumerable.");
+ }
+ if (!desc.configurable) {
+ $ERROR("Property " + property + " must be configurable.");
+ }
+ var value = desc.value;
+ var isValid = (typeof valid === "function") ? valid(value) : (valid.indexOf(value) !== -1);
+ if (!isValid) {
+ $ERROR("Property value " + value + " is not allowed for property " + property + ".");
+ }
+}
+
+
+/**
+ * Tests whether the named property of the given object, if present at all, has a valid value
+ * and the default attributes of the properties of an object literal.
+ * @param {Object} obj the object to be tested.
+ * @param {string} property the name of the property
+ * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
+ * an array of valid values.
+ * @exception if the property is present and has an invalid value.
+ */
+function mayHaveProperty(obj, property, valid) {
+ if (obj.hasOwnProperty(property)) {
+ testProperty(obj, property, valid);
+ }
+}
+
+
+/**
+ * Tests whether the given object has the named property with a valid value
+ * and the default attributes of the properties of an object literal.
+ * @param {Object} obj the object to be tested.
+ * @param {string} property the name of the property
+ * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
+ * an array of valid values.
+ * @exception if the property is missing or has an invalid value.
+ */
+function mustHaveProperty(obj, property, valid) {
+ if (!obj.hasOwnProperty(property)) {
+ $ERROR("Object is missing property " + property + ".");
+ }
+ testProperty(obj, property, valid);
+}
+
+
+/**
+ * Tests whether the given object does not have the named property.
+ * @param {Object} obj the object to be tested.
+ * @param {string} property the name of the property
+ * @exception if the property is present.
+ */
+function mustNotHaveProperty(obj, property) {
+ if (obj.hasOwnProperty(property)) {
+ $ERROR("Object has property it mustn't have: " + property + ".");
+ }
+}
+
+
+/**
+ * Properties of the RegExp constructor that may be affected by use of regular
+ * expressions, and the default values of these properties. Properties are from
+ * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties
+ */
+var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+ "$_", "$*", "$&", "$+", "$`", "$'",
+ "input", "lastMatch", "lastParen", "leftContext", "rightContext"
+];
+
+var regExpPropertiesDefaultValues = (function () {
+ var values = Object.create(null);
+ regExpProperties.forEach(function (property) {
+ values[property] = RegExp[property];
+ });
+ return values;
+}());
+
+
+/**
+ * Tests that executing the provided function (which may use regular expressions
+ * in its implementation) does not create or modify unwanted properties on the
+ * RegExp constructor.
+ */
+function testForUnwantedRegExpChanges(testFunc) {
+ regExpProperties.forEach(function (property) {
+ RegExp[property] = regExpPropertiesDefaultValues[property];
+ });
+ testFunc();
+ regExpProperties.forEach(function (property) {
+ if (RegExp[property] !== regExpPropertiesDefaultValues[property]) {
+ $ERROR("RegExp has unexpected property " + property + " with value " +
+ RegExp[property] + ".");
+ }
+ });
+}
+
+
+/**
+ * Tests whether name is a valid BCP 47 numbering system name
+ * and not excluded from use in the ECMAScript Internationalization API.
+ * @param {string} name the name to be tested.
+ * @return {boolean} whether name is a valid BCP 47 numbering system name and
+ * allowed for use in the ECMAScript Internationalization API.
+ */
+
+function isValidNumberingSystem(name) {
+
+ // source: CLDR file common/bcp47/number.xml; version CLDR 21.
+ var numberingSystems = [
+ "arab",
+ "arabext",
+ "armn",
+ "armnlow",
+ "bali",
+ "beng",
+ "brah",
+ "cakm",
+ "cham",
+ "deva",
+ "ethi",
+ "finance",
+ "fullwide",
+ "geor",
+ "grek",
+ "greklow",
+ "gujr",
+ "guru",
+ "hanidec",
+ "hans",
+ "hansfin",
+ "hant",
+ "hantfin",
+ "hebr",
+ "java",
+ "jpan",
+ "jpanfin",
+ "kali",
+ "khmr",
+ "knda",
+ "osma",
+ "lana",
+ "lanatham",
+ "laoo",
+ "latn",
+ "lepc",
+ "limb",
+ "mlym",
+ "mong",
+ "mtei",
+ "mymr",
+ "mymrshan",
+ "native",
+ "nkoo",
+ "olck",
+ "orya",
+ "roman",
+ "romanlow",
+ "saur",
+ "shrd",
+ "sora",
+ "sund",
+ "talu",
+ "takr",
+ "taml",
+ "tamldec",
+ "telu",
+ "thai",
+ "tibt",
+ "traditio",
+ "vaii"
+ ];
+
+ var excluded = [
+ "finance",
+ "native",
+ "traditio"
+ ];
+
+
+ return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1;
+}
+
+
+/**
+ * Provides the digits of numbering systems with simple digit mappings,
+ * as specified in 11.3.2.
+ */
+
+var numberingSystemDigits = {
+ arab: "٠١٢٣٤٥٦٧٨٩",
+ arabext: "۰۱۲۳۴۵۶۷۸۹",
+ beng: "০১২৩৪৫৬৭৮৯",
+ deva: "०१२३४५६७८९",
+ fullwide: "0123456789",
+ gujr: "૦૧૨૩૪૫૬૭૮૯",
+ guru: "੦੧੨੩੪੫੬੭੮੯",
+ hanidec: "〇一二三四五六七八九",
+ khmr: "០១២៣៤៥៦៧៨៩",
+ knda: "೦೧೨೩೪೫೬೭೮೯",
+ laoo: "໐໑໒໓໔໕໖໗໘໙",
+ latn: "0123456789",
+ mlym: "൦൧൨൩൪൫൬൭൮൯",
+ mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙",
+ mymr: "၀၁၂၃၄၅၆၇၈၉",
+ orya: "୦୧୨୩୪୫୬୭୮୯",
+ tamldec: "௦௧௨௩௪௫௬௭௮௯",
+ telu: "౦౧౨౩౪౫౬౭౮౯",
+ thai: "๐๑๒๓๔๕๖๗๘๙",
+ tibt: "༠༡༢༣༤༥༦༧༨༩"
+};
+
+
+/**
+ * Tests that number formatting is handled correctly. The function checks that the
+ * digit sequences in formatted output are as specified, converted to the
+ * selected numbering system, and embedded in consistent localized patterns.
+ * @param {Array} locales the locales to be tested.
+ * @param {Array} numberingSystems the numbering systems to be tested.
+ * @param {Object} options the options to pass to Intl.NumberFormat. Options
+ * must include {useGrouping: false}, and must cause 1.1 to be formatted
+ * pre- and post-decimal digits.
+ * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings
+ * in unlocalized format with Western digits.
+ */
+
+function testNumberFormat(locales, numberingSystems, options, testData) {
+ locales.forEach(function (locale) {
+ numberingSystems.forEach(function (numbering) {
+ var digits = numberingSystemDigits[numbering];
+ var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options);
+
+ function getPatternParts(positive) {
+ var n = positive ? 1.1 : -1.1;
+ var formatted = format.format(n);
+ var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)";
+ var match = formatted.match(new RegExp(oneoneRE));
+ if (match === null) {
+ $ERROR("Unexpected formatted " + n + " for " +
+ format.resolvedOptions().locale + " and options " +
+ JSON.stringify(options) + ": " + formatted);
+ }
+ return match;
+ }
+
+ function toNumbering(raw) {
+ return raw.replace(/[0-9]/g, function (digit) {
+ return digits[digit.charCodeAt(0) - "0".charCodeAt(0)];
+ });
+ }
+
+ function buildExpected(raw, patternParts) {
+ var period = raw.indexOf(".");
+ if (period === -1) {
+ return patternParts[1] + toNumbering(raw) + patternParts[3];
+ } else {
+ return patternParts[1] +
+ toNumbering(raw.substring(0, period)) +
+ patternParts[2] +
+ toNumbering(raw.substring(period + 1)) +
+ patternParts[3];
+ }
+ }
+
+ if (format.resolvedOptions().numberingSystem === numbering) {
+ // figure out prefixes, infixes, suffixes for positive and negative values
+ var posPatternParts = getPatternParts(true);
+ var negPatternParts = getPatternParts(false);
+
+ Object.getOwnPropertyNames(testData).forEach(function (input) {
+ var rawExpected = testData[input];
+ var patternParts;
+ if (rawExpected[0] === "-") {
+ patternParts = negPatternParts;
+ rawExpected = rawExpected.substring(1);
+ } else {
+ patternParts = posPatternParts;
+ }
+ var expected = buildExpected(rawExpected, patternParts);
+ var actual = format.format(input);
+ if (actual !== expected) {
+ $ERROR("Formatted value for " + input + ", " +
+ format.resolvedOptions().locale + " and options " +
+ JSON.stringify(options) + " is " + actual + "; expected " + expected + ".");
+ }
+ });
+ }
+ });
+ });
+}
+
+
+/**
+ * Return the components of date-time formats.
+ * @return {Array} an array with all date-time components.
+ */
+
+function getDateTimeComponents() {
+ return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
+}
+
+
+/**
+ * Return the valid values for the given date-time component, as specified
+ * by the table in section 12.1.1.
+ * @param {string} component a date-time component.
+ * @return {Array} an array with the valid values for the component.
+ */
+
+function getDateTimeComponentValues(component) {
+
+ var components = {
+ weekday: ["narrow", "short", "long"],
+ era: ["narrow", "short", "long"],
+ year: ["2-digit", "numeric"],
+ month: ["2-digit", "numeric", "narrow", "short", "long"],
+ day: ["2-digit", "numeric"],
+ hour: ["2-digit", "numeric"],
+ minute: ["2-digit", "numeric"],
+ second: ["2-digit", "numeric"],
+ timeZoneName: ["short", "long"]
+ };
+
+ var result = components[component];
+ if (result === undefined) {
+ $ERROR("Internal error: No values defined for date-time component " + component + ".");
+ }
+ return result;
+}
+
+
+/**
+ * Tests that the given value is valid for the given date-time component.
+ * @param {string} component a date-time component.
+ * @param {string} value the value to be tested.
+ * @return {boolean} true if the test succeeds.
+ * @exception if the test fails.
+ */
+
+function testValidDateTimeComponentValue(component, value) {
+ if (getDateTimeComponentValues(component).indexOf(value) === -1) {
+ $ERROR("Invalid value " + value + " for date-time component " + component + ".");
+ }
+ return true;
+}
+
+
+/**
+ * Verifies that the actual array matches the expected one in length, elements,
+ * and element order.
+ * @param {Array} expected the expected array.
+ * @param {Array} actual the actual array.
+ * @return {boolean} true if the test succeeds.
+ * @exception if the test fails.
+ */
+function testArraysAreSame(expected, actual) {
+ for (i = 0; i < Math.max(actual.length, expected.length); i++) {
+ if (actual[i] !== expected[i]) {
+ $ERROR("Result array element at index " + i + " should be \"" +
+ expected[i] + "\" but is \"" + actual[i] + "\".");
+ }
+ }
+ return true;
+}
+