PluralRules.js 8.7 KB

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