Bug 1263040 - Add Intl.getCanonicalLocales. r=waldo
☠☠ backed out by fbd4d72adc4c ☠ ☠
authorZibi Braniecki <gandalf@mozilla.com>
Tue, 12 Apr 2016 10:36:43 -0700
changeset 316670 716d75c8abc204d419caa0c28f9fd0e63dd5a609
parent 316632 fb125ff927eae1b7adb8d0e3db798c341d71d8ab
child 316671 bd86df4974b41780cf523a3f63c49f2a137a40a3
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs1263040
milestone48.0a1
Bug 1263040 - Add Intl.getCanonicalLocales. r=waldo
js/src/builtin/Intl.cpp
js/src/builtin/Intl.js
js/src/tests/Intl/getCanonicalLocales-overriden-arg-length.js
js/src/tests/Intl/getCanonicalLocales-overriden-push.js
js/src/tests/Intl/getCanonicalLocales-overriden-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
@@ -2341,16 +2341,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-overriden-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-overriden-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-overriden-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" ||