package summer.phrasebook class PluralRulesSpec extends munit.FunSuite: // --- getPluralIndex tests --- test("English: 2 forms (singular/plural)") { assertEquals(PluralRules.getPluralIndex("en", 0), 1) assertEquals(PluralRules.getPluralIndex("en", 1), 0) assertEquals(PluralRules.getPluralIndex("en", 2), 1) assertEquals(PluralRules.getPluralIndex("en", 100), 1) } test("French: 0 and 1 are singular") { assertEquals(PluralRules.getPluralIndex("fr", 0), 0) assertEquals(PluralRules.getPluralIndex("fr", 1), 0) assertEquals(PluralRules.getPluralIndex("fr", 2), 1) assertEquals(PluralRules.getPluralIndex("fr", 5), 1) } test("Polish: 3 forms (one/few/many)") { assertEquals(PluralRules.getPluralIndex("pl", 1), 0) // one assertEquals(PluralRules.getPluralIndex("pl", 2), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 3), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 4), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 5), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 10), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 11), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 12), 2) // many (12-14 are exceptions) assertEquals(PluralRules.getPluralIndex("pl", 13), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 14), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 22), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 23), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 24), 1) // few assertEquals(PluralRules.getPluralIndex("pl", 25), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 100), 2) // many assertEquals(PluralRules.getPluralIndex("pl", 112), 2) // many (n%100=12, exception) } test("Russian: 3 forms (Slavic rule)") { assertEquals(PluralRules.getPluralIndex("ru", 1), 0) // one assertEquals(PluralRules.getPluralIndex("ru", 2), 1) // few assertEquals(PluralRules.getPluralIndex("ru", 5), 2) // many assertEquals(PluralRules.getPluralIndex("ru", 11), 2) // many (exception: 11-19) assertEquals(PluralRules.getPluralIndex("ru", 21), 0) // one assertEquals(PluralRules.getPluralIndex("ru", 22), 1) // few assertEquals(PluralRules.getPluralIndex("ru", 25), 2) // many assertEquals(PluralRules.getPluralIndex("ru", 111), 2) // many (n%100=11) assertEquals(PluralRules.getPluralIndex("ru", 121), 0) // one (n%10=1, n%100=21) } test("Czech: 3 forms") { assertEquals(PluralRules.getPluralIndex("cs", 1), 0) assertEquals(PluralRules.getPluralIndex("cs", 2), 1) assertEquals(PluralRules.getPluralIndex("cs", 4), 1) assertEquals(PluralRules.getPluralIndex("cs", 5), 2) assertEquals(PluralRules.getPluralIndex("cs", 100), 2) } test("Japanese: no plural (always 0)") { assertEquals(PluralRules.getPluralIndex("ja", 0), 0) assertEquals(PluralRules.getPluralIndex("ja", 1), 0) assertEquals(PluralRules.getPluralIndex("ja", 100), 0) } test("Chinese: no plural (always 0)") { assertEquals(PluralRules.getPluralIndex("zh", 0), 0) assertEquals(PluralRules.getPluralIndex("zh", 1), 0) assertEquals(PluralRules.getPluralIndex("zh", 42), 0) } test("Arabic: 6 forms") { assertEquals(PluralRules.getPluralIndex("ar", 0), 0) // zero assertEquals(PluralRules.getPluralIndex("ar", 1), 1) // one assertEquals(PluralRules.getPluralIndex("ar", 2), 2) // two assertEquals(PluralRules.getPluralIndex("ar", 3), 3) // few (3-10) assertEquals(PluralRules.getPluralIndex("ar", 10), 3) // few assertEquals(PluralRules.getPluralIndex("ar", 11), 4) // many (11-99) assertEquals(PluralRules.getPluralIndex("ar", 99), 4) // many assertEquals(PluralRules.getPluralIndex("ar", 100), 5) // other (100+) assertEquals(PluralRules.getPluralIndex("ar", 1000), 5) // other } test("Slovenian: 4 forms") { assertEquals(PluralRules.getPluralIndex("sl", 1), 0) // n%100==1 assertEquals(PluralRules.getPluralIndex("sl", 2), 1) // n%100==2 assertEquals(PluralRules.getPluralIndex("sl", 3), 2) // n%100==3 or 4 assertEquals(PluralRules.getPluralIndex("sl", 4), 2) assertEquals(PluralRules.getPluralIndex("sl", 5), 3) // other assertEquals(PluralRules.getPluralIndex("sl", 101), 0) // n%100==1 assertEquals(PluralRules.getPluralIndex("sl", 102), 1) // n%100==2 } test("Welsh: 4 forms") { assertEquals(PluralRules.getPluralIndex("cy", 1), 0) assertEquals(PluralRules.getPluralIndex("cy", 2), 1) assertEquals(PluralRules.getPluralIndex("cy", 8), 2) assertEquals(PluralRules.getPluralIndex("cy", 11), 2) assertEquals(PluralRules.getPluralIndex("cy", 5), 3) } test("Maltese: 4 forms") { assertEquals(PluralRules.getPluralIndex("mt", 1), 0) // one assertEquals(PluralRules.getPluralIndex("mt", 0), 1) // few (0, or n%100 2-10) assertEquals(PluralRules.getPluralIndex("mt", 2), 1) // few assertEquals(PluralRules.getPluralIndex("mt", 10), 1) // few assertEquals(PluralRules.getPluralIndex("mt", 11), 2) // many (n%100 11-19) assertEquals(PluralRules.getPluralIndex("mt", 19), 2) // many assertEquals(PluralRules.getPluralIndex("mt", 20), 3) // other } test("Lithuanian: 3 forms") { assertEquals(PluralRules.getPluralIndex("lt", 1), 0) // one (n%10==1, not 11) assertEquals(PluralRules.getPluralIndex("lt", 2), 1) // few (n%10>=2, n%100<10 or >=20) assertEquals(PluralRules.getPluralIndex("lt", 10), 2) // other assertEquals(PluralRules.getPluralIndex("lt", 11), 2) // exception assertEquals(PluralRules.getPluralIndex("lt", 21), 0) // one assertEquals(PluralRules.getPluralIndex("lt", 12), 2) // exception (n%100 in 10-19) } test("Latvian: 3 forms") { assertEquals(PluralRules.getPluralIndex("lv", 0), 0) // zero assertEquals(PluralRules.getPluralIndex("lv", 1), 1) // one (n%10==1, not 11) assertEquals(PluralRules.getPluralIndex("lv", 2), 2) // other assertEquals(PluralRules.getPluralIndex("lv", 11), 2) // other (exception) assertEquals(PluralRules.getPluralIndex("lv", 21), 1) // one } test("Romanian: 3 forms") { assertEquals(PluralRules.getPluralIndex("ro", 1), 0) // one assertEquals(PluralRules.getPluralIndex("ro", 0), 1) // few (0 or n%100 1-19) assertEquals(PluralRules.getPluralIndex("ro", 19), 1) // few assertEquals(PluralRules.getPluralIndex("ro", 20), 2) // other assertEquals(PluralRules.getPluralIndex("ro", 100), 2) // other } test("Macedonian: last digit rule") { assertEquals(PluralRules.getPluralIndex("mk", 1), 0) // n%10==1 assertEquals(PluralRules.getPluralIndex("mk", 2), 1) assertEquals(PluralRules.getPluralIndex("mk", 11), 0) // n%10==1 assertEquals(PluralRules.getPluralIndex("mk", 21), 0) // n%10==1 } test("Irish: 3 forms") { assertEquals(PluralRules.getPluralIndex("ga", 1), 0) assertEquals(PluralRules.getPluralIndex("ga", 2), 1) assertEquals(PluralRules.getPluralIndex("ga", 3), 2) } test("locale with region uses language portion") { // pt_BR should use "pt" rules (2 forms) assertEquals(PluralRules.getPluralIndex("pt_BR", 1), 0) assertEquals(PluralRules.getPluralIndex("pt_BR", 2), 1) } test("unknown locale returns 0") { assertEquals(PluralRules.getPluralIndex("xx", 5), 0) } test("negative numbers use absolute value") { assertEquals(PluralRules.getPluralIndex("en", -1), 0) assertEquals(PluralRules.getPluralIndex("en", -5), 1) } // --- choose() tests --- test("choose with simple English plural") { val en = LocaleTag("en") assertEquals(PluralRules.choose("item|items", 1, en), "item") assertEquals(PluralRules.choose("item|items", 0, en), "items") assertEquals(PluralRules.choose("item|items", 5, en), "items") } test("choose with explicit conditions") { val en = LocaleTag("en") assertEquals(PluralRules.choose("{0} No items|{1} One item|[2,*] Many items", 0, en), "No items") assertEquals(PluralRules.choose("{0} No items|{1} One item|[2,*] Many items", 1, en), "One item") assertEquals(PluralRules.choose("{0} No items|{1} One item|[2,*] Many items", 5, en), "Many items") assertEquals(PluralRules.choose("{0} No items|{1} One item|[2,*] Many items", 100, en), "Many items") } test("choose with explicit range") { val en = LocaleTag("en") assertEquals(PluralRules.choose("[1,3] Few|[4,*] Many", 2, en), "Few") assertEquals(PluralRules.choose("[1,3] Few|[4,*] Many", 4, en), "Many") } test("choose with Polish 3 forms") { val pl = LocaleTag("pl") val line = "wpis|wpisy|wpisów" assertEquals(PluralRules.choose(line, 1, pl), "wpis") assertEquals(PluralRules.choose(line, 2, pl), "wpisy") assertEquals(PluralRules.choose(line, 5, pl), "wpisów") assertEquals(PluralRules.choose(line, 22, pl), "wpisy") assertEquals(PluralRules.choose(line, 12, pl), "wpisów") } test("choose with Arabic 6 forms") { val ar = LocaleTag("ar") val line = "zero|one|two|few|many|other" assertEquals(PluralRules.choose(line, 0, ar), "zero") assertEquals(PluralRules.choose(line, 1, ar), "one") assertEquals(PluralRules.choose(line, 2, ar), "two") assertEquals(PluralRules.choose(line, 5, ar), "few") assertEquals(PluralRules.choose(line, 50, ar), "many") assertEquals(PluralRules.choose(line, 100, ar), "other") } test("choose falls back to last segment if index out of bounds") { val en = LocaleTag("en") // Only 1 segment but English wants index 1 for n!=1 assertEquals(PluralRules.choose("only one form", 5, en), "only one form") }