common.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  6. const constructors = [Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat];
  7. if (WScript.Platform.INTL_LIBRARY === "icu") {
  8. constructors.push(Intl.PluralRules);
  9. }
  10. testRunner.runTests([
  11. {
  12. name: "OSS-Fuzz #6657: stress uloc_forLanguageTag status code and parsed length on duplicate variant subtags",
  13. body() {
  14. function test(Ctor, locale) {
  15. assert.throws(() => new Ctor(locale), RangeError, `new Intl.${Ctor.name}("${locale}") should throw`);
  16. }
  17. function testWithVariants(variants) {
  18. for (const Ctor of constructors) {
  19. for (let i = 0; i < variants.length; ++i) {
  20. for (let k = 0; k < variants.length; ++k) {
  21. for (let m = 0; m < variants.length; ++m) {
  22. test(Ctor, `und-${variants[i]}-${variants[k]}-${variants[m]}`);
  23. test(Ctor, `en-${variants[i]}-${variants[k]}-${variants[m]}`);
  24. test(Ctor, `de-DE-${variants[i]}-${variants[k]}-${variants[m]}`);
  25. test(Ctor, `zh-Hans-CN-${variants[i]}-${variants[k]}-${variants[m]}`);
  26. }
  27. test(Ctor, `und-${variants[i]}-${variants[k]}`);
  28. test(Ctor, `en-${variants[i]}-${variants[k]}`);
  29. test(Ctor, `de-DE-${variants[i]}-${variants[k]}`);
  30. test(Ctor, `zh-Hans-CN-${variants[i]}-${variants[k]}`);
  31. }
  32. }
  33. }
  34. }
  35. if (WScript.Platform.INTL_LIBRARY === "icu") {
  36. testWithVariants(["gregory", "GREGORY", "gregORY"]);
  37. testWithVariants(["invalid", "INVALID", "invaLID"]);
  38. }
  39. }
  40. },
  41. {
  42. name: "OSS-Fuzz #7950: Have option getters redefine themselves",
  43. body() {
  44. if (WScript.Platform.INTL_LIBRARY === "winglob") {
  45. return;
  46. }
  47. function test(callback, optionName, optionValue, shouldCallSecondGetter) {
  48. const options = {};
  49. let calledSecondGetter = false;
  50. Object.defineProperty(options, optionName, {
  51. get() {
  52. Object.defineProperty(options, optionName, {
  53. get() {
  54. calledSecondGetter = true;
  55. return undefined;
  56. }
  57. });
  58. return optionValue;
  59. },
  60. configurable: true
  61. });
  62. callback(options);
  63. assert.areEqual(shouldCallSecondGetter, calledSecondGetter, "Second getter behavior was incorrect");
  64. }
  65. test((options) => assert.areEqual(1, new Intl.Collator("en-US", options).compare("A", "a")), "sensitivity", "case", false);
  66. test((options) => assert.areEqual(-1, new Intl.Collator("en-US", options).compare("A", "B")), "sensitivity", "case", false);
  67. test((options) => assert.areEqual(0, new Intl.Collator("en-US", options).compare("a", "\u00E2")), "sensitivity", "case", false);
  68. test((options) => assert.areEqual("1000", new Intl.NumberFormat("en-US", options).format(1000)), "useGrouping", false, false);
  69. test((options) => assert.areEqual("$1.50", new Intl.NumberFormat("en-US", Object.assign(options, { currency: "USD" })).format(1.5)), "style", "currency", false);
  70. // This was the original bug - at present, all browsers format the string as "" because the value returned by the second getter dictates format selection
  71. test((options) => assert.areEqual("", new Intl.DateTimeFormat("en-US", options).format()), "year", "numeric", true);
  72. test((options) => assert.areEqual("", new Intl.DateTimeFormat("en-US", options).format()), "minute", "numeric", true);
  73. }
  74. },
  75. {
  76. name: "Intl.FallbackSymbol behavior",
  77. body() {
  78. if (WScript.Platform.INTL_LIBRARY === "winglob") {
  79. return;
  80. }
  81. function testFallbackSymbol(Ctor, shouldHaveFallbackSymbol) {
  82. const objNew = new Ctor();
  83. const objCall = Ctor.call(objNew);
  84. const symbols = Object.getOwnPropertySymbols(objCall);
  85. assert.isTrue(objCall instanceof Ctor, `The given object should be an instance of ${Ctor.name}`);
  86. assert.areEqual(0, Object.getOwnPropertyNames(objCall).length, "Incorrect number of OwnPropertyNames");
  87. if (shouldHaveFallbackSymbol) {
  88. assert.areEqual(1, symbols.length, "Incorrect number of OwnPropertySymbols");
  89. const fallbackSymbol = symbols[0];
  90. assert.areEqual("Symbol(Intl.FallbackSymbol)", fallbackSymbol.toString(), "Unexpected symbol description");
  91. assert.areEqual("object", typeof objCall[fallbackSymbol], "objCall[fallbackSymbol] should be an object");
  92. assert.isTrue(objCall[fallbackSymbol] instanceof Ctor, `objCall[fallbackSymbol] should be an instance of ${Ctor.name}`);
  93. assert.throws(() => Ctor.call(objNew), TypeError, "Should not be able to legacy-construct an already-legacy-constructed Intl object (using original non-legacy new object)", "Cannot modify non-writable property 'Intl.FallbackSymbol'");
  94. assert.throws(() => Ctor.call(objCall), TypeError, "Should not be able to legacy-construct an already-legacy-constructed Intl object (using legacy .call() object", "Cannot modify non-writable property 'Intl.FallbackSymbol'");
  95. assert.areEqual(objNew, objCall, "Object created with .call should return `this`");
  96. } else {
  97. assert.areEqual(0, symbols.length, "Incorrect number of OwnPropertySymbols");
  98. }
  99. }
  100. // only NumberFormat and DateTimeFormat should have Intl.FallbackSymbol behavior. PluralRules has no legacy construction behavior.
  101. testFallbackSymbol(Intl.Collator, false);
  102. testFallbackSymbol(Intl.NumberFormat, true);
  103. testFallbackSymbol(Intl.DateTimeFormat, true);
  104. assert.throws(() => Intl.PluralRules.call(new Intl.PluralRules()), TypeError, "Intl.PluralRules requires `new`");
  105. }
  106. }
  107. ], { verbose: false });