PluralRules.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. function testData(locale, ordinals, cardinals) {
  8. const plOrdinal = new Intl.PluralRules(locale, { type: "ordinal" });
  9. const plCardinal = new Intl.PluralRules(locale, { type: "cardinal" });
  10. assert.areEqual(locale, plOrdinal.resolvedOptions().locale);
  11. assert.areEqual(locale, plCardinal.resolvedOptions().locale);
  12. ordinals.forEach((ordinal, i) => ordinal !== undefined && assert.areEqual(ordinal, plOrdinal.select(i), `Selecting ${i} for locale ${locale} with ordinal type`));
  13. cardinals.forEach((cardinal, i) => cardinal !== undefined && assert.areEqual(cardinal, plCardinal.select(i), `Selecting ${i} for locale ${locale} with cardinal type`));
  14. }
  15. testRunner.runTests([
  16. {
  17. name: "Basic resolved options",
  18. body() {
  19. const pr = new Intl.PluralRules("en");
  20. const opts = pr.resolvedOptions();
  21. assert.areEqual("string", typeof opts.locale, "Locale should be the default locale");
  22. assert.areEqual("cardinal", opts.type, "Default type should be cardinal");
  23. assert.areEqual(1, opts.minimumIntegerDigits, "Default minimumIntegerDigits should be 1");
  24. assert.areEqual(0, opts.minimumFractionDigits, "Default minimumFractionDigits should be 0");
  25. assert.areEqual(3, opts.maximumFractionDigits, "Default maximumFractionDigits should be 3");
  26. const acceptableCategories = ["zero", "one", "two", "few", "many", "other"];
  27. assert.isTrue(Array.isArray(opts.pluralCategories), "pluralCategories should always be an array");
  28. opts.pluralCategories.forEach((category) => assert.isTrue(acceptableCategories.includes(category)));
  29. if (WScript.Platform.ICU_VERSION >= 61) {
  30. // In ICU 61+, uplrules_getKeywords became stable, so we can actually use it
  31. // REVIEW(jahorto): In all locales, there should be at least a singular and plural category?
  32. assert.isTrue(opts.pluralCategories.length >= 2, "pluralCategories should use uplrules_getKeywords");
  33. } else {
  34. assert.isTrue(opts.pluralCategories.length === 1, "pluralCategories should not use uplrules_getKeywords");
  35. }
  36. }
  37. },
  38. {
  39. name: "pluralCategories",
  40. body() {
  41. assert.areEqual("en-US", Intl.PluralRules.supportedLocalesOf("en-US")[0], "PluralRules must support en-US for these tests");
  42. function test(pr, categories) {
  43. if (WScript.Platform.ICU_VERSION >= 61) {
  44. const resolvedCategories = pr.resolvedOptions().pluralCategories;
  45. assert.areEqual(categories.length, resolvedCategories.length);
  46. for (const c of resolvedCategories) {
  47. assert.isTrue(categories.includes(c));
  48. }
  49. }
  50. for (let i = 0; i < 15; i++) {
  51. assert.isTrue(categories.includes(pr.select(i)), `Incorrect value for select(${i})`);
  52. }
  53. }
  54. test(new Intl.PluralRules("en-US"), ["other", "one"]);
  55. test(new Intl.PluralRules("en-US", { type: "ordinal" }), ["few", "one", "two", "other"]);
  56. }
  57. },
  58. {
  59. name: "Welsh data tests",
  60. body() {
  61. const ordinals = ["zero", "one", "two", "few", "few", "many", "many", "zero", "zero", "zero", "other"];
  62. const cardinals = ["zero", "one", "two", "few", "other", "other", "many", "other", "other", "other"];
  63. testData("cy", ordinals, cardinals);
  64. }
  65. },
  66. {
  67. name: "Slovenian data tests",
  68. body() {
  69. const ordinals = Array(10).fill("other");
  70. const cardinals = ["other", "one", "two", "few", "few", "other"];
  71. cardinals[10] = "other";
  72. cardinals[11] = "other";
  73. cardinals[12] = "other";
  74. cardinals[13] = "other";
  75. cardinals[14] = "other";
  76. cardinals[15] = "other";
  77. cardinals[100] = "other";
  78. cardinals[101] = "one";
  79. cardinals[102] = "two";
  80. cardinals[103] = "few";
  81. cardinals[104] = "few";
  82. cardinals[105] = "other";
  83. testData("sl", ordinals, cardinals);
  84. }
  85. },
  86. {
  87. name: "https://github.com/tc39/ecma402/issues/224",
  88. body() {
  89. const pr1 = new Intl.PluralRules();
  90. const pr2 = new Intl.PluralRules();
  91. const opts1 = pr1.resolvedOptions();
  92. const opts2 = pr2.resolvedOptions();
  93. assert.isFalse(opts1.pluralCategories === opts2.pluralCategories, "Different PluralRules instances should have different category array instances");
  94. opts1.pluralCategories.forEach((cat, i) => {
  95. assert.areEqual(cat, opts2.pluralCategories[i], "Different PluralRules instances should have the same category array contents");
  96. });
  97. assert.isFalse(opts1.pluralCategories === pr1.resolvedOptions().pluralCategories, "Calling resolvedOptions again on the same PluralRules instance should return a new array instance");
  98. opts1.pluralCategories[0] = "changed";
  99. assert.areNotEqual(opts1.pluralCategories[0], pr1.resolvedOptions().pluralCategories[0], "Changing the pluralCategories from one call to resolvedOptions should not impact future calls");
  100. }
  101. },
  102. {
  103. name: "Number digit options",
  104. body() {
  105. function test(options, n, expected) {
  106. const pr = new Intl.PluralRules("en", options);
  107. const res = pr.resolvedOptions();
  108. assert.areEqual(expected, pr.select(n), `Incorrect result using n = ${n} and options = ${JSON.stringify(options)}`);
  109. // We should only report sigfigs in the resolved options if they were asked for https://github.com/tc39/ecma402/issues/244
  110. if (options.minimumSignificantDigits !== undefined || options.maximumSignificantDigits !== undefined) {
  111. if (options.minimumSignificantDigits !== undefined) {
  112. assert.areEqual(options.minimumSignificantDigits, res.minimumSignificantDigits, "Incorrect minimumSignificantDigits");
  113. }
  114. if (options.maximumSignificantDigits !== undefined) {
  115. assert.areEqual(options.maximumSignificantDigits, res.maximumSignificantDigits, "Incorrect maximumSignificantDigits");
  116. }
  117. } else {
  118. assert.isFalse(res.hasOwnProperty("minimumSignificantDigits"), "Reported minimumSignificantDigits when it shouldn't have been");
  119. assert.isFalse(res.hasOwnProperty("maximumSignificantDigits"), "Reported maximumSignificantDigits when it shouldn't have been");
  120. }
  121. }
  122. test({}, 1.0, "one");
  123. test({}, 1.1, "other");
  124. test({}, 1.001, "other");
  125. test({ minimumFractionDigits: 1 }, 1.0, "one");
  126. test({ minimumFractionDigits: 1 }, 1.1, "other");
  127. test({ minimumFractionDigits: 1 }, 1.001, "other");
  128. test({ maximumFractionDigits: 0 }, 1.0, "one");
  129. test({ maximumFractionDigits: 0 }, 1.1, "one");
  130. test({ maximumFractionDigits: 0 }, 1.001, "one");
  131. test({ maximumFractionDigits: 1 }, 1.0, "one");
  132. test({ maximumFractionDigits: 1 }, 1.1, "other");
  133. test({ maximumFractionDigits: 1 }, 1.001, "one");
  134. test({ minimumSignificantDigits: 2 }, 1.0, "one");
  135. test({ minimumSignificantDigits: 2 }, 1.1, "other");
  136. test({ minimumSignificantDigits: 2 }, 1.001, "other");
  137. test({ maximumSignificantDigits: 2 }, 1.0, "one");
  138. test({ maximumSignificantDigits: 2 }, 1.1, "other");
  139. test({ maximumSignificantDigits: 2 }, 1.001, "one");
  140. test({ maximumSignificantDigits: 1 }, 1.0, "one");
  141. test({ maximumSignificantDigits: 1 }, 1.1, "one");
  142. test({ maximumSignificantDigits: 1 }, 1.001, "one");
  143. test({ maximumSignificantDigits: 1 }, 110.001, "other");
  144. test({ maximumSignificantDigits: 1 }, -110.001, "other");
  145. test({ maximumSignificantDigits: 1 }, -1, "one");
  146. // significantDigits should override fractionDigits and integerDigits
  147. test({ maximumSignificantDigits: 2, maximumFractionDigits: 0 }, 1.1, "other");
  148. }
  149. },
  150. ], { verbose: false });