Bug 1263040 - Add Intl.getCanonicalLocales. r=jwalden
authorZibi Braniecki <gandalf@mozilla.com>
Tue, 12 Apr 2016 10:36:43 -0700
changeset 332075 b6cd434fdaf5f9471c4f17e23876143718a1e3c0
parent 332074 5177d7cdb97fb0616b27a877047c4f08a67e5fdc
child 332076 41dfd4ad33b7d3c5f5809e659a8066bf778a9fbf
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1263040
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1263040 - Add Intl.getCanonicalLocales. r=jwalden
js/src/builtin/Intl.cpp
js/src/builtin/Intl.js
js/src/tests/Intl/getCanonicalLocales-overridden-arg-length.js
js/src/tests/Intl/getCanonicalLocales-overridden-push.js
js/src/tests/Intl/getCanonicalLocales-overridden-set.js
js/src/tests/Intl/getCanonicalLocales-weird-cases.js
js/src/tests/Intl/getCanonicalLocales-with-duplicates.js
js/src/tests/Intl/getCanonicalLocales.js
js/src/tests/Intl/shell.js
js/src/tests/shell.js
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -2348,16 +2348,17 @@ intl_toSource(JSContext* cx, unsigned ar
     return true;
 }
 #endif
 
 static const JSFunctionSpec intl_static_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  intl_toSource,        0, 0),
 #endif
+    JS_SELF_HOSTED_FN("getCanonicalLocales", "Intl_getCanonicalLocales", 1, 0),
     JS_FS_END
 };
 
 /**
  * Initializes the Intl Object and its standard built-in properties.
  * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1
  */
 JSObject*
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -2879,8 +2879,22 @@ function resolveICUPattern(pattern, resu
                 _DefineDataProperty(result, icuPatternCharToComponent[c], value);
             if (c === "h" || c === "K")
                 _DefineDataProperty(result, "hour12", true);
             else if (c === "H" || c === "k")
                 _DefineDataProperty(result, "hour12", false);
         }
     }
 }
+
+function Intl_getCanonicalLocales(locales) {
+  let codes = CanonicalizeLocaleList(locales);
+  let result = [];
+
+  let len = codes.length;
+  let k = 0;
+
+  while (k < len) {
+    _DefineDataProperty(result, k, codes[k]);
+    k++;
+  }
+  return result;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-overridden-arg-length.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Tests the getCanonicalLocales function for overridden argument's length.
+
+var count = 0;
+var locs = { get length() { if (count++ > 0) throw 42; return 0; } };
+var locales = Intl.getCanonicalLocales(locs); // shouldn't throw 42
+assertEq(locales.length, 0);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-overridden-push.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Tests the getCanonicalLocales function for overriden Array.push.
+
+Array.prototype.push = () => { throw 42; };
+
+// must not throw 42, might if push is used
+var arr = Intl.getCanonicalLocales(["en-US"]);
+
+assertShallowArray(arr, ["en-US"]);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-overridden-set.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Tests the getCanonicalLocales function for overridden set().
+
+Object.defineProperty(Array.prototype, 0, { set() { throw 42; } });
+
+// must not throw 42, might if push is used
+var arr = Intl.getCanonicalLocales(["en-US"]);
+
+assertShallowArray(arr, ["en-US"]);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-weird-cases.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Locale processing is supposed to internally remove any Unicode extension
+// sequences in the locale.  Test that various weird testcases invoking
+// algorithmic edge cases don't assert or throw exceptions.
+
+var weirdCases =
+  [
+   "x-u-foo",
+   "en-x-u-foo",
+   "en-a-bar-x-u-foo",
+   "en-x-u-foo-a-bar",
+   "en-a-bar-u-baz-x-u-foo",
+  ];
+
+for (let weird of weirdCases)
+  assertShallowArray(Intl.getCanonicalLocales(weird), [weird]);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
+
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-with-duplicates.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Tests the getCanonicalLocales function for duplicate locales scenario.
+
+assertShallowArray(
+  Intl.getCanonicalLocales(
+    ['ab-cd', 'ff', 'de-rt', 'ab-Cd']), ['ab-CD', 'ff', 'de-RT']);
+
+var locales = Intl.getCanonicalLocales(["en-US", "en-US"]);
+assertShallowArray(locales, ['en-US']);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+/* 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/. */
+
+// Tests the getCanonicalLocales function with a diverse set of arguments.
+
+let gCL = Intl.getCanonicalLocales;
+
+assertEq(Intl.getCanonicalLocales.length, 1);
+
+assertShallowArray(gCL(), []);
+
+assertShallowArray(gCL('ab-cd'), ['ab-CD']);
+
+assertShallowArray(gCL(['ab-cd']), ['ab-CD']);
+
+assertShallowArray(gCL(['ab-cd', 'FF']), ['ab-CD', 'ff']);
+
+assertShallowArray(gCL({'a': 0}), []);
+
+assertShallowArray(gCL({}), []);
+
+assertShallowArray(gCL(['ar-ma-u-ca-islamicc']), ['ar-MA-u-ca-islamicc']);
+
+assertShallowArray(gCL(['th-th-u-nu-thai']), ['th-TH-u-nu-thai']);
+
+assertShallowArray(gCL(NaN), []);
+
+assertShallowArray(gCL(1), []);
+
+Number.prototype[0] = "en-US";
+Number.prototype.length = 1;
+assertShallowArray(gCL(NaN), ["en-US"]);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
--- a/js/src/tests/Intl/shell.js
+++ b/js/src/tests/Intl/shell.js
@@ -0,0 +1,9 @@
+if (typeof assertShallowArray === 'undefined') {
+  var assertShallowArray = function assertShallowArray(actual, expected) {
+    var len = actual.length;
+    assertEq(len, expected.length, "mismatching array lengths");
+
+    for (var i = 0; i < len; i++)
+      assertEq(actual[i], expected[i], "mismatch at element " + i);
+  }
+}
--- a/js/src/tests/shell.js
+++ b/js/src/tests/shell.js
@@ -73,17 +73,26 @@ function TestCase(n, d, e, a)
   this.name = n;
   this.description = d;
   this.expect = e;
   this.actual = a;
   this.passed = getTestCaseResult(e, a);
   this.reason = '';
   this.bugnumber = typeof(BUGNUMER) != 'undefined' ? BUGNUMBER : '';
   this.type = (typeof window == 'undefined' ? 'shell' : 'browser');
-  gTestcases[gTc++] = this;
+  ({}).constructor.defineProperty(
+    gTestcases,
+    gTc++,
+    {
+      value: this,
+      enumerable: true,
+      configurable: true,
+      writable: true
+    }
+  );
 }
 
 gFailureExpected = false;
 
 TestCase.prototype.dump = function () {
   // let reftest handle error reporting, otherwise
   // output a summary line.
   if (typeof document != "object" ||