Espruino/tests/test_262.js
Gordon Williams a0dee715d3 Fixed massive regression I'd just introduced in Exceptions
Fixed overriding of builtins with other Builtins
Added Date.valueOf
Added 262 test, which checks a lot of standard JS before even starting each small test
2014-06-13 18:22:30 +01:00

2234 lines
69 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Simple test from http://test262.ecmascript.org/#
// Just checking whether Espruino is capable of running the tests or not
// NOTE: RegEx checks have been removed here and 'result=1' was put at the end
var strict_mode = false;
function testRun(id, path, description, codeString, result, error) {
if (result!=="pass") {
throw new Error("Test '" + path + "'failed: " + error);
}
}
function testFinished() {
//no-op
}
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!");
}
}
if (this.window!==undefined) { //for console support
this.window.onerror = function(errorMsg, url, lineNumber) {
this.window.iframeError = errorMsg;
};
}
//This doesn't work with early errors in current versions of Opera
/*
if (/opera/i.test(navigator.userAgent)) {
(function() {
var origError = window.Error;
window.Error = function() {
if (arguments.length>0) {
try {
window.onerror(arguments[0]);
} catch(e) {
alert("Failed to invoke window.onerror (from ed.js)");
}
}
return origError.apply(this, arguments);
}
})();
}*/
/**
* @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;
}
/**
* 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
*/
// CHANGE GW
/*
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: "",
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;
}
function testcase() {
/*MultiLine
Comments
\u2028 var = ;
*/
return true;
}
runTestCase(testcase);
// CHANGE GW
result = 1;