17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2007-2014, International Business Machines Corporation and 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.dev.test.format; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ByteArrayInputStream; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ByteArrayOutputStream; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInputStream; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectOutputStream; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.Serializable; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParseException; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Arrays; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collections; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Comparator; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.EnumSet; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashSet; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashSet; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map.Entry; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeMap; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeSet; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.test.TestFmwk; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.test.serializable.SerializableTest; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.util.CollectionUtilities; 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.util.Relation; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.Utility; 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.NumberFormat; 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules; 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.FixedDecimal; 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.FixedDecimalRange; 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.FixedDecimalSamples; 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.KeywordStatus; 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.PluralType; 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.SampleType; 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.UFieldPosition; 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Output; 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author dougfelt (Doug Felt) 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author markdavis (Mark Davis) [for fractional support] 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class PluralRulesTest extends TestFmwk { 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRulesFactory factory = PluralRulesFactory.NORMAL; 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static void main(String[] args) throws Exception { 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new PluralRulesTest().run(args); 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testOverUnderflow() { 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln(String.valueOf(Long.MAX_VALUE + 1d)); 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (double[] testDouble : new double[][] { 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1E18, 0, 0, 1E18 }, // check overflow 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 10000000000000.1d, 1, 1, 10000000000000d }, { -0.00001d, 1, 5, 0 }, { 1d, 0, 0, 1 }, 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1.1d, 1, 1, 1 }, { 12345d, 0, 0, 12345 }, { 12345.678912d, 678912, 6, 12345 }, 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 12345.6789123d, 678912, 6, 12345 }, // we only go out 6 digits 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1E18, 0, 0, 1E18 }, // check overflow 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1E19, 0, 0, 1E18 }, // check overflow 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }) { 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal fd = new FixedDecimal(testDouble[0]); 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + "=doubleValue()", testDouble[0], fd.doubleValue()); 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + " decimalDigits", (int) testDouble[1], fd.decimalDigits); 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + " visibleDecimalDigitCount", (int) testDouble[2], fd.visibleDecimalDigitCount); 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + " decimalDigitsWithoutTrailingZeros", (int) testDouble[1], 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fd.decimalDigitsWithoutTrailingZeros); 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + " visibleDecimalDigitCountWithoutTrailingZeros", (int) testDouble[2], 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fd.visibleDecimalDigitCountWithoutTrailingZeros); 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(testDouble[0] + " integerValue", (long) testDouble[3], fd.integerValue); 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : new ULocale[] { ULocale.ENGLISH, new ULocale("cy"), new ULocale("ar") }) { 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = factory.forLocale(locale); 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(locale + " NaN", "other", rules.select(Double.NaN)); 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(locale + " ∞", "other", rules.select(Double.POSITIVE_INFINITY)); 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(locale + " -∞", "other", rules.select(Double.NEGATIVE_INFINITY)); 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testSyntaxRestrictions() { 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object[][] shouldFail = { 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n in 3..10,13..19" }, 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // = and != always work 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n=1" }, 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n=1,3" }, 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n!=1" }, 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n!=1,3" }, 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // with spacing 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1" }, 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1, 3" }, 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n != 1" }, 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n != 1, 3" }, 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! = 1" }, 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! = 1, 3" }, 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1 , 3" }, 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n != 1 , 3" }, 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! = 1 , 3" }, 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1 .. 3" }, 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n != 1 .. 3" }, 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! = 1 .. 3" }, 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // more complicated 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n in 3 .. 10 , 13 .. 19" }, 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // singles have special exceptions 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n is 1" }, 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n is not 1" }, 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not is 1", ParseException.class }, // hacked to fail 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n in 1" }, 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not in 1" }, 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // multiples also have special exceptions 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO enable the following once there is an update to CLDR 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // {"a: n is 1,3", ParseException.class}, 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n is not 1,3", ParseException.class }, // hacked to fail 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not is 1,3", ParseException.class }, // hacked to fail 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n in 1,3" }, 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not in 1,3" }, 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // disallow not with = 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not= 1", ParseException.class }, // hacked to fail 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not= 1,3", ParseException.class }, // hacked to fail 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // disallow double negatives 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! is not 1", ParseException.class }, 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n ! is not 1", ParseException.class }, 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n not not in 1", ParseException.class }, 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n is not not 1", NumberFormatException.class }, 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // disallow screwy cases 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { null, NullPointerException.class }, { "djkl;", ParseException.class }, 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1 .", ParseException.class }, { "a: n = 1 ..", ParseException.class }, 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n = 1 2", ParseException.class }, { "a: n = 1 ,", ParseException.class }, 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a:n in 3 .. 10 , 13 .. 19 ,", ParseException.class }, }; 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object[] shouldFailTest : shouldFail) { 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String rules = (String) shouldFailTest[0]; 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Class exception = shouldFailTest.length < 2 ? null : (Class) shouldFailTest[1]; 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Class actualException = null; 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules.parseDescription(rules); 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert actualException = e.getClass(); 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("Exception " + rules, exception, actualException); 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testSamples() { 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String description = "one: n is 3 or f is 5 @integer 3,19, @decimal 3.50 ~ 3.53, …; other: @decimal 99.0~99.2, 999.0, …"; 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules test = PluralRules.createRules(description); 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkNewSamples(description, test, "one", PluralRules.SampleType.INTEGER, "@integer 3, 19", true, 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new FixedDecimal(3)); 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkNewSamples(description, test, "one", PluralRules.SampleType.DECIMAL, "@decimal 3.50~3.53, …", false, 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new FixedDecimal(3.5, 2)); 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkOldSamples(description, test, "one", SampleType.INTEGER, 3d, 19d); 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkOldSamples(description, test, "one", SampleType.DECIMAL, 3.5d, 3.51d, 3.52d, 3.53d); 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkNewSamples(description, test, "other", PluralRules.SampleType.INTEGER, "", true, null); 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkNewSamples(description, test, "other", PluralRules.SampleType.DECIMAL, "@decimal 99.0~99.2, 999.0, …", 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert false, new FixedDecimal(99d, 1)); 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkOldSamples(description, test, "other", SampleType.INTEGER); 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkOldSamples(description, test, "other", SampleType.DECIMAL, 99d, 99.1, 99.2d, 999d); 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void checkOldSamples(String description, PluralRules rules, String keyword, SampleType sampleType, 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Double... expected) { 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> oldSamples = rules.getSamples(keyword, sampleType); 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!assertEquals("getOldSamples; " + keyword + "; " + description, new HashSet(Arrays.asList(expected)), 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert oldSamples)) { 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules.getSamples(keyword, sampleType); 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void checkNewSamples(String description, PluralRules test, String keyword, SampleType sampleType, 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String samplesString, boolean isBounded, FixedDecimal firstInRange) { 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String title = description + ", " + sampleType; 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples samples = test.getDecimalSamples(keyword, sampleType); 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (samples != null) { 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("samples; " + title, samplesString, samples.toString()); 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("bounded; " + title, isBounded, samples.bounded); 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("first; " + title, firstInRange, samples.samples.iterator().next().start); 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("limited: " + title, isBounded, test.isLimited(keyword, sampleType)); 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] parseTestData = { "a: n is 1", "a:1", "a: n mod 10 is 2", "a:2,12,22", 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n is not 1", "a:0,2,3,4,5", "a: n mod 3 is not 1", "a:0,2,3,5,6,8,9", "a: n in 2..5", "a:2,3,4,5", 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n within 2..5", "a:2,3,4,5", "a: n not in 2..5", "a:0,1,6,7,8", "a: n not within 2..5", "a:0,1,6,7,8", 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 10 in 2..5", "a:2,3,4,5,12,13,14,15,22,23,24,25", "a: n mod 10 within 2..5", 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a:2,3,4,5,12,13,14,15,22,23,24,25", "a: n mod 10 is 2 and n is not 12", "a:2,22,32,42", 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 10 in 2..3 or n mod 10 is 5", "a:2,3,5,12,13,15,22,23,25", 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 10 within 2..3 or n mod 10 is 5", "a:2,3,5,12,13,15,22,23,25", "a: n is 1 or n is 4 or n is 23", 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a:1,4,23", "a: n mod 2 is 1 and n is not 3 and n in 1..11", "a:1,5,7,9,11", 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 2 is 1 and n is not 3 and n within 1..11", "a:1,5,7,9,11", 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 2 is 1 or n mod 5 is 1 and n is not 6", "a:1,3,5,7,9,11,13,15,16", 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..5; b: n in 5..8; c: n mod 2 is 1", "a:2,3,4,5;b:6,7,8;c:1,9,11", 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n within 2..5; b: n within 5..8; c: n mod 2 is 1", "a:2,3,4,5;b:6,7,8;c:1,9,11", 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2,4..6; b: n within 7..9,11..12,20", "a:2,4,5,6;b:7,8,9,11,12,20", 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..8,12 and n not in 4..6", "a:2,3,7,8,12", "a: n mod 10 in 2,3,5..7 and n is not 12", 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a:2,3,5,6,7,13,15,16,17", "a: n in 2..6,3..7", "a:2,3,4,5,6,7", }; 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String[] getTargetStrings(String targets) { 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List list = new ArrayList(50); 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] valSets = Utility.split(targets, ';'); 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < valSets.length; ++i) { 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] temp = Utility.split(valSets[i], ':'); 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String key = temp[0].trim(); 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] vals = Utility.split(temp[1], ','); 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = 0; j < vals.length; ++j) { 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String valString = vals[j].trim(); 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int val = Integer.parseInt(valString); 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (list.size() <= val) { 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert list.add(null); 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (list.get(val) != null) { 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fail("test data error, key: " + list.get(val) + " already set for: " + val); 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert list.set(val, key); 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] result = (String[]) list.toArray(new String[list.size()]); 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < result.length; ++i) { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result[i] == null) { 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result[i] = "other"; 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void checkTargets(PluralRules rules, String[] targets) { 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < targets.length; ++i) { 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("value " + i, targets[i], rules.select(i)); 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testParseEmpty() throws ParseException { 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = PluralRules.parseDescription("a:n"); 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("empty", "a", rules.select(0)); 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testParsing() { 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < parseTestData.length; i += 2) { 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String pattern = parseTestData[i]; 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String expected = parseTestData[i + 1]; 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("pattern[" + i + "] " + pattern); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = PluralRules.createRules(pattern); 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] targets = getTargetStrings(expected); 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkTargets(rules, targets); 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert e.printStackTrace(); 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e.getMessage()); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String[][] operandTestData = { { "a: n 3", "FAIL" }, 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n=1,2; b: n != 3..5; c:n!=5", "a:1,2; b:6,7; c:3,4" }, 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n=1,2; b: n!=3..5; c:n!=5", "a:1,2; b:6,7; c:3,4" }, 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: t is 1", "a:1.1,1.1000,99.100; other:1.2,1.0" }, { "a: f is 1", "a:1.1; other:1.1000,99.100" }, 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: i is 2; b:i is 3", "b: 3.5; a: 2.5" }, { "a: f is 0; b:f is 50", "a: 1.00; b: 1.50" }, 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: v is 1; b:v is 2", "a: 1.0; b: 1.00" }, { "one: n is 1 AND v is 0", "one: 1 ; other: 1.00,1.0" }, // English 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // rules 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "one: v is 0 and i mod 10 is 1 or f mod 10 is 1", "one: 1, 1.1, 3.1; other: 1.0, 3.2, 5" }, // Last 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // visible 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // digit 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "one: j is 0", "one: 0; other: 0.0, 1.0, 3" }, // Last visible digit 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // one → n is 1; few → n in 2..4; 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testOperands() { 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String[] pair : operandTestData) { 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String pattern = pair[0].trim(); 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String categoriesAndExpected = pair[1].trim(); 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // logln("pattern[" + i + "] " + pattern); 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean FAIL_EXPECTED = categoriesAndExpected.equalsIgnoreCase("fail"); 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln(pattern); 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = PluralRules.createRules(pattern); 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (FAIL_EXPECTED) { 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNull("Should fail with 'null' return.", rules); 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln(rules == null ? "null rules" : rules.toString()); 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkCategoriesAndExpected(pattern, categoriesAndExpected, rules); 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!FAIL_EXPECTED) { 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert e.printStackTrace(); 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e.getMessage()); 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testUniqueRules() { 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert main: for (ULocale locale : factory.getAvailableULocales()) { 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = factory.forLocale(locale); 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<String, PluralRules> keywordToRule = new HashMap<String, PluralRules>(); 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<FixedDecimalSamples> samples = new LinkedHashSet<FixedDecimalSamples>(); 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String keyword : rules.getKeywords()) { 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (SampleType sampleType : SampleType.values()) { 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples samples2 = rules.getDecimalSamples(keyword, sampleType); 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (samples2 != null) { 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert samples.add(samples2); 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword.equals("other")) { 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String rules2 = keyword + ":" + rules.getRules(keyword); 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules singleRule = PluralRules.createRules(rules2); 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (singleRule == null) { 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Can't generate single rule for " + rules2); 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules.createRules(rules2); // for debugging 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue main; 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywordToRule.put(keyword, singleRule); 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<FixedDecimal, String> collisionTest = new TreeMap(); 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FixedDecimalSamples sample3 : samples) { 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<FixedDecimalRange> samples2 = sample3.getSamples(); 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (samples2 == null) { 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FixedDecimalRange sample : samples2) { 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < 1; ++i) { 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal item = i == 0 ? sample.start : sample.end; 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collisionTest.clear(); 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Entry<String, PluralRules> entry : keywordToRule.entrySet()) { 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rule = entry.getValue(); 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String foundKeyword = rule.select(item); 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (foundKeyword.equals("other")) { 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String old = collisionTest.get(item); 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (old != null) { 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln(locale + "\tNon-unique rules: " + item + " => " + old + " & " + foundKeyword); 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rule.select(item); 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collisionTest.put(item, foundKeyword); 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void checkCategoriesAndExpected(String title1, String categoriesAndExpected, PluralRules rules) { 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String categoryAndExpected : categoriesAndExpected.split("\\s*;\\s*")) { 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] categoryFromExpected = categoryAndExpected.split("\\s*:\\s*"); 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String expected = categoryFromExpected[0]; 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String value : categoryFromExpected[1].split("\\s*,\\s*")) { 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (value.startsWith("@") || value.equals("…") || value.equals("null")) { 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] values = value.split("\\s*~\\s*"); 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkValue(title1, rules, expected, values[0]); 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (values.length > 1) { 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkValue(title1, rules, expected, values[1]); 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void checkValue(String title1, PluralRules rules, String expected, String value) { 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double number = Double.parseDouble(value); 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int decimalPos = value.indexOf('.') + 1; 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int countVisibleFractionDigits; 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int fractionaldigits; 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (decimalPos == 0) { 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert countVisibleFractionDigits = fractionaldigits = 0; 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert countVisibleFractionDigits = value.length() - decimalPos; 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fractionaldigits = Integer.parseInt(value.substring(decimalPos)); 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String result = rules.select(number, countVisibleFractionDigits, fractionaldigits); 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale = null; 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage(title1, locale, rules, expected) + "; value: " + value, expected, result); 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String[][] equalityTestData = { 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // once we add fractions, we had to retract the "test all possibilities" for equality, 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // so we only have a limited set of equality tests now. 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "c: n%11!=5", "c: n mod 11 is not 5" }, { "c: n is not 7", "c: n != 7" }, { "a:n in 2;", "a: n = 2" }, 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "b:n not in 5;", "b: n != 5" }, 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // { "a: n is 5", 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n in 2..6 and n not in 2..4 and n is not 6" }, 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // { "a: n in 2..3", 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n is 2 or n is 3", 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n is 3 and n in 2..5 or n is 2" }, 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // { "a: n is 12; b:n mod 10 in 2..3", 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "b: n mod 10 in 2..3 and n is not 12; a: n in 12..12", 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "b: n is 13; a: n is 12; b: n mod 10 is 2 or n mod 10 is 3" }, 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String[][] inequalityTestData = { { "a: n mod 8 is 3", "a: n mod 7 is 3" }, 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n mod 3 is 2 and n is not 5", "a: n mod 6 is 2 or n is 8 or n is 11" }, 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the following are currently inequal, but we may make them equal in the future. 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "a: n in 2..5", "a: n in 2..4,5" }, }; 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void compareEquality(String id, Object[] objects, boolean shouldBeEqual) { 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < objects.length; ++i) { 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object lhs = objects[i]; 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int start = shouldBeEqual ? i : i + 1; 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = start; j < objects.length; ++j) { 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object rhs = objects[j]; 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rhs == null || shouldBeEqual != lhs.equals(rhs)) { 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String msg = shouldBeEqual ? "should be equal" : "should not be equal"; 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fail(id + " " + msg + " (" + i + ", " + j + "):\n " + lhs + "\n " + rhs); 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assertEquals("obj " + i + " and " + j, lhs, rhs); 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void compareEqualityTestSets(String[][] sets, boolean shouldBeEqual) { 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < sets.length; ++i) { 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] patterns = sets[i]; 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules[] rules = new PluralRules[patterns.length]; 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = 0; j < patterns.length; ++j) { 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[j] = PluralRules.createRules(patterns[j]); 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert compareEquality("test " + i, rules, shouldBeEqual); 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testEquality() { 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert compareEqualityTestSets(equalityTestData, true); 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testInequality() { 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert compareEqualityTestSets(inequalityTestData, false); 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testBuiltInRules() { 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // spot check 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = factory.forLocale(ULocale.US); 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("us 0", PluralRules.KEYWORD_OTHER, rules.select(0)); 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("us 1", PluralRules.KEYWORD_ONE, rules.select(1)); 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("us 2", PluralRules.KEYWORD_OTHER, rules.select(2)); 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules = factory.forLocale(ULocale.JAPAN); 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ja 0", PluralRules.KEYWORD_OTHER, rules.select(0)); 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ja 1", PluralRules.KEYWORD_OTHER, rules.select(1)); 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ja 2", PluralRules.KEYWORD_OTHER, rules.select(2)); 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules = factory.forLocale(ULocale.createCanonical("ru")); 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ru 0", PluralRules.KEYWORD_MANY, rules.select(0)); 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ru 1", PluralRules.KEYWORD_ONE, rules.select(1)); 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ru 2", PluralRules.KEYWORD_FEW, rules.select(2)); 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testFunctionalEquivalent() { 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // spot check 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale unknown = ULocale.createCanonical("zz_ZZ"); 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale un_equiv = PluralRules.getFunctionalEquivalent(unknown, null); 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("unknown locales have root", ULocale.ROOT, un_equiv); 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale jp_equiv = PluralRules.getFunctionalEquivalent(ULocale.JAPAN, null); 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale cn_equiv = PluralRules.getFunctionalEquivalent(ULocale.CHINA, null); 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("japan and china equivalent locales", jp_equiv, cn_equiv); 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean[] available = new boolean[1]; 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale russia = ULocale.createCanonical("ru_RU"); 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale ru_ru_equiv = PluralRules.getFunctionalEquivalent(russia, available); 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertFalse("ru_RU not listed", available[0]); 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale russian = ULocale.createCanonical("ru"); 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale ru_equiv = PluralRules.getFunctionalEquivalent(russian, available); 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertTrue("ru listed", available[0]); 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("ru and ru_RU equivalent locales", ru_ru_equiv, ru_equiv); 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testAvailableULocales() { 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale[] locales = factory.getAvailableULocales(); 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set localeSet = new HashSet(); 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeSet.addAll(Arrays.asList(locales)); 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("locales are unique in list", locales.length, localeSet.size()); 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Test the method public static PluralRules parseDescription(String description) 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestParseDescription() { 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (PluralRules.DEFAULT != PluralRules.parseDescription("")) { 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("PluralRules.parseDescription(String) was suppose " 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + "to return PluralRules.DEFAULT when String is of " + "length 0."); 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (ParseException e) { 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("PluralRules.parseDescription(String) was not suppose " + "to return an exception."); 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Tests the method public static PluralRules createRules(String description) 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestCreateRules() { 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (PluralRules.createRules(null) != null) { 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("PluralRules.createRules(String) was suppose to " 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + "return null for an invalid String descrtiption."); 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Tests the method public int hashCode() 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestHashCode() { 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Bad test, breaks whenever PluralRules implementation changes. 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // PluralRules pr = PluralRules.DEFAULT; 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (106069776 != pr.hashCode()) { 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // errln("PluralRules.hashCode() was suppose to return 106069776 " + "when PluralRules.DEFAULT."); 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Tests the method public boolean equals(PluralRules rhs) 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestEquals() { 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pr = PluralRules.DEFAULT; 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pr.equals((PluralRules) null)) { 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("PluralRules.equals(PluralRules) was supposed to return false " + "when passing null."); 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void assertRuleValue(String rule, double value) { 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleKeyValue("a:" + rule, "a", value); 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void assertRuleKeyValue(String rule, String key, double value) { 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pr = PluralRules.createRules(rule); 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(rule, value, pr.getUniqueKeywordValue(key)); 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Tests getUniqueKeywordValue() 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestGetUniqueKeywordValue() { 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleKeyValue("a: n is 1", "not_defined", PluralRules.NO_UNIQUE_VALUE); // key not defined 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n within 2..2", 2); 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 1", 1); 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n in 2..2", 2); 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n in 3..4", PluralRules.NO_UNIQUE_VALUE); 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n within 3..4", PluralRules.NO_UNIQUE_VALUE); 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 or n is 2", 2); 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 and n is 2", 2); 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 or n is 3", PluralRules.NO_UNIQUE_VALUE); 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 and n is 3", PluralRules.NO_UNIQUE_VALUE); 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 or n in 2..3", PluralRules.NO_UNIQUE_VALUE); 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n is 2 and n in 2..3", 2); 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleKeyValue("a: n is 1", "other", PluralRules.NO_UNIQUE_VALUE); // key matches default rule 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n in 2,3", PluralRules.NO_UNIQUE_VALUE); 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertRuleValue("n in 2,3..6 and n not in 2..3,5..6", 4); 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The version in PluralFormatUnitTest is not really a test, and it's in the wrong place anyway, so I'm putting a 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * variant of it here. 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestGetSamples() { 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<ULocale> uniqueRuleSet = new HashSet<ULocale>(); 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : factory.getAvailableULocales()) { 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueRuleSet.add(PluralRules.getFunctionalEquivalent(locale, null)); 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : uniqueRuleSet) { 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = factory.forLocale(locale); 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("\nlocale: " + (locale == ULocale.ROOT ? "root" : locale.toString()) + ", rules: " + rules); 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> keywords = rules.getKeywords(); 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String keyword : keywords) { 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> list = rules.getSamples(keyword); 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("keyword: " + keyword + ", samples: " + list); 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // with fractions, the samples can be empty and thus the list null. In that case, however, there will be 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // FixedDecimal values. 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // So patch the test for that. 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (list.size() == 0) { 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // when the samples (meaning integer samples) are null, then then integerSamples must be, and the 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // decimalSamples must not be 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples integerSamples = rules.getDecimalSamples(keyword, SampleType.INTEGER); 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples decimalSamples = rules.getDecimalSamples(keyword, SampleType.DECIMAL); 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertTrue(getAssertMessage("List is not null", locale, rules, keyword), integerSamples == null 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && decimalSamples != null && decimalSamples.samples.size() != 0); 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!assertTrue(getAssertMessage("Test getSamples.isEmpty", locale, rules, keyword), 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert !list.isEmpty())) { 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules.getSamples(keyword); 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rules.toString().contains(": j")) { 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hack until we remove j 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (double value : list) { 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("Match keyword", locale, rules, keyword) + "; value '" 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + value + "'", keyword, rules.select(value)); 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNull(locale + ", list is null", rules.getSamples("@#$%^&*")); 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNull(locale + ", list is null", rules.getSamples("@#$%^&*", SampleType.DECIMAL)); 6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getAssertMessage(String message, ULocale locale, PluralRules rules, String keyword) { 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String ruleString = ""; 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword != null) { 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword.equals("other")) { 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String keyword2 : rules.getKeywords()) { 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleString += " NOR " + rules.getRules(keyword2).split("@")[0]; 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String rule = rules.getRules(keyword); 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleString = rule == null ? null : rule.split("@")[0]; 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleString = "; rule: '" + keyword + ": " + ruleString + "'"; 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // !keyword.equals("other") ? "'; keyword: '" + keyword + "'; rule: '" + rules.getRules(keyword) + "'" 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // : "'; keyword: '" + keyword + "'; rules: '" + rules.toString() + "'"; 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return message + (locale == null ? "" : "; locale: '" + locale + "'") + ruleString; 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the empty set if the keyword is not defined, null if there are an unlimited number of values for the 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword, or the set of values that trigger the keyword. 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestGetAllKeywordValues() { 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // data is pairs of strings, the rule, and the expected values as arguments 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] data = { 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "other: ; a: n mod 3 is 0", 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: null", 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..5 and n within 5..8", 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: 5", 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..5", 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: 2,3,4,5; other: null", 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n not in 2..5", 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: null; other: null", 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n within 2..5", 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: 2,3,4,5; other: null", 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n not within 2..5", 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: null; other: null", 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..5 or n within 6..8", 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: 2,3,4,5,6,7,8", // ignore 'other' here on out, always null 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n in 2..5 and n within 6..8", 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: null", 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we no longer support 'degenerate' rules 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n within 2..5 and n within 6..8", "a:", // our sampling catches these 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n within 2..5 and n within 5..8", "a: 5", // '' 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5", "a: 2,4", 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "a: n mod 3 is 0 and n within 0..5", "a: 0,3", 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5 or n within 5..6 and n within 6..7", 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: 2,4,6", // but not this... 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 3 is 0 and n within 1..2", "a: null", "a: n mod 3 is 0 and n within 0..6", "a: 0,3,6", 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "a: n mod 3 is 0 and n in 3..12", "a: 3,6,9,12", "a: n in 2,4..6 and n is not 5", "a: 2,4,6", }; 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < data.length; i += 2) { 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String ruleDescription = data[i]; 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String result = data[i + 1]; 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules p = PluralRules.createRules(ruleDescription); 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (p == null) { // for debugging 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules.createRules(ruleDescription); 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String ruleResult : result.split(";")) { 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] ruleAndValues = ruleResult.split(":"); 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = ruleAndValues[0].trim(); 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String valueList = ruleAndValues.length < 2 ? null : ruleAndValues[1]; 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (valueList != null) { 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueList = valueList.trim(); 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> values; 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (valueList == null || valueList.length() == 0) { 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values = Collections.EMPTY_SET; 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ("null".equals(valueList)) { 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values = null; 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values = new TreeSet<Double>(); 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String value : valueList.split(",")) { 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values.add(Double.parseDouble(value)); 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> results = p.getAllKeywordValues(keyword); 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(keyword + " in " + ruleDescription, values, results == null ? null : new HashSet(results)); 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (results != null) { 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results.add(PluralRules.NO_UNIQUE_VALUE); 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fail("returned set is modifiable"); 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (UnsupportedOperationException e) { 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // pass 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestOrdinal() { 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pr = factory.forLocale(ULocale.ENGLISH, PluralType.ORDINAL); 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("PluralRules(en-ordinal).select(2)", "two", pr.select(2)); 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestBasicFraction() { 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[][] tests = { { "en", "one: j is 1" }, { "1", "0", "1", "one" }, { "1", "2", "1.00", "other" }, }; 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale = null; 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumberFormat nf = null; 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pr = null; 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String[] row : tests) { 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (row.length) { 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 2: 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locale = ULocale.forLanguageTag(row[0]); 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nf = NumberFormat.getInstance(locale); 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pr = PluralRules.createRules(row[1]); 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 4: 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double n = Double.parseDouble(row[0]); 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minFracDigits = Integer.parseInt(row[1]); 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nf.setMinimumFractionDigits(minFracDigits); 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String expectedFormat = row[2]; 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String expectedKeyword = row[3]; 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UFieldPosition pos = new UFieldPosition(); 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String formatted = nf.format(1.0, new StringBuffer(), pos).toString(); 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int countVisibleFractionDigits = pos.getCountVisibleFractionDigits(); 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long fractionDigits = pos.getFractionDigits(); 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = pr.select(n, countVisibleFractionDigits, fractionDigits); 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("Formatted " + n + "\t" + minFracDigits, expectedFormat, formatted); 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("Keyword " + n + "\t" + minFracDigits, expectedKeyword, keyword); 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(); 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestLimitedAndSamplesConsistency() { 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : PluralRules.getAvailableULocales()) { 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale loc2 = PluralRules.getFunctionalEquivalent(locale, null); 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!loc2.equals(locale)) { 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; // only need "unique" rules 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (PluralType type : PluralType.values()) { 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = PluralRules.forLocale(locale, type); 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (SampleType sampleType : SampleType.values()) { 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (sampleType == SampleType.DECIMAL && type == PluralType.ORDINAL) { 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logKnownIssue("10783", "Fix issues with isLimited vs computeLimited on ordinals"); 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String keyword : rules.getKeywords()) { 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isLimited = rules.isLimited(keyword, sampleType); 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean computeLimited = rules.computeLimited(keyword, sampleType); 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!keyword.equals("other")) { 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("computeLimited == isLimited", locale, rules, keyword), 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert computeLimited, isLimited); 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> samples = rules.getSamples(keyword, sampleType); 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNotNull(getAssertMessage("Samples must not be null", locale, rules, keyword), samples); 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* FixedDecimalSamples decimalSamples = */rules.getDecimalSamples(keyword, sampleType); 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assertNotNull(getAssertMessage("Decimal samples must be null if unlimited", locale, rules, 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // keyword), decimalSamples); 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestKeywords() { 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> possibleKeywords = new LinkedHashSet(Arrays.asList("zero", "one", "two", "few", "many", "other")); 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object[][][] tests = { 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // format is locale, explicits, then triples of keyword, status, unique value. 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { { "en", null }, { "one", KeywordStatus.UNIQUE, 1.0d }, { "other", KeywordStatus.UNBOUNDED, null } }, 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { { "pl", null }, { "one", KeywordStatus.UNIQUE, 1.0d }, { "few", KeywordStatus.UNBOUNDED, null }, 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "many", KeywordStatus.UNBOUNDED, null }, 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "other", KeywordStatus.SUPPRESSED, null, KeywordStatus.UNBOUNDED, null } // note that it is 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // suppressed in 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // INTEGER but not 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // DECIMAL 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }, { { "en", new HashSet<Double>(Arrays.asList(1.0d)) }, // check that 1 is suppressed 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "one", KeywordStatus.SUPPRESSED, null }, { "other", KeywordStatus.UNBOUNDED, null } }, }; 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Output<Double> uniqueValue = new Output<Double>(); 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object[][] test : tests) { 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale = new ULocale((String) test[0][0]); 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // NumberType numberType = (NumberType) test[1]; 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<Double> explicits = (Set<Double>) test[0][1]; 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pluralRules = factory.forLocale(locale); 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LinkedHashSet<String> remaining = new LinkedHashSet(possibleKeywords); 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 1; i < test.length; ++i) { 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object[] row = test[i]; 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = (String) row[0]; 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert KeywordStatus statusExpected = (KeywordStatus) row[1]; 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Double uniqueExpected = (Double) row[2]; 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert remaining.remove(keyword); 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert KeywordStatus status = pluralRules.getKeywordStatus(keyword, 0, explicits, uniqueValue); 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("Unique Value", locale, pluralRules, keyword), uniqueExpected, 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueValue.value); 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("Keyword Status", locale, pluralRules, keyword), statusExpected, status); 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (row.length > 3) { 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert statusExpected = (KeywordStatus) row[3]; 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueExpected = (Double) row[4]; 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert status = pluralRules.getKeywordStatus(keyword, 0, explicits, uniqueValue, SampleType.DECIMAL); 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("Unique Value - decimal", locale, pluralRules, keyword), 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueExpected, uniqueValue.value); 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals(getAssertMessage("Keyword Status - decimal", locale, pluralRules, keyword), 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert statusExpected, status); 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String keyword : remaining) { 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert KeywordStatus status = pluralRules.getKeywordStatus(keyword, 0, null, uniqueValue); 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("Invalid keyword " + keyword, status, KeywordStatus.INVALID); 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNull("Invalid keyword " + keyword, uniqueValue.value); 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert enum StandardPluralCategories { 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert zero, one, two, few, many, other; 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Set<StandardPluralCategories> ALL = Collections.unmodifiableSet(EnumSet 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert .allOf(StandardPluralCategories.class)); 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a mutable set 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param source 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final EnumSet<StandardPluralCategories> getSet(Collection<String> source) { 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumSet<StandardPluralCategories> result = EnumSet.noneOf(StandardPluralCategories.class); 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String s : source) { 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(StandardPluralCategories.valueOf(s)); 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Comparator<Set<StandardPluralCategories>> SHORTEST_FIRST = new Comparator<Set<StandardPluralCategories>>() { 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compare(Set<StandardPluralCategories> arg0, Set<StandardPluralCategories> arg1) { 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int diff = arg0.size() - arg1.size(); 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (diff != 0) { 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return diff; 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // otherwise first... 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // could be optimized, but we don't care here. 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (StandardPluralCategories value : ALL) { 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (arg0.contains(value)) { 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!arg1.contains(value)) { 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 1; 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (arg1.contains(value)) { 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestLocales() { 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (false) { 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert generateLOCALE_SNAPSHOT(); 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String test : LOCALE_SNAPSHOT) { 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert test = test.trim(); 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] parts = test.split("\\s*;\\s*"); 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String localeString : parts[0].split("\\s*,\\s*")) { 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale = new ULocale(localeString); 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (factory.hasOverride(locale)) { 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; // skip for now 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = factory.forLocale(locale); 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 1; i < parts.length; ++i) { 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkCategoriesAndExpected(localeString, parts[i], rules); 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Comparator<PluralRules> PLURAL_RULE_COMPARATOR = new Comparator<PluralRules>() { 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compare(PluralRules o1, PluralRules o2) { 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return o1.compareTo(o2); 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void generateLOCALE_SNAPSHOT() { 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Comparator c = new CollectionUtilities.CollectionComparator<Comparable>(); 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Relation<Set<StandardPluralCategories>, PluralRules> setsToRules = Relation.of( 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new TreeMap<Set<StandardPluralCategories>, Set<PluralRules>>(c), TreeSet.class, PLURAL_RULE_COMPARATOR); 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Relation<PluralRules, ULocale> data = Relation.of( 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new TreeMap<PluralRules, Set<ULocale>>(PLURAL_RULE_COMPARATOR), TreeSet.class); 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : PluralRules.getAvailableULocales()) { 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules pr = PluralRules.forLocale(locale); 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumSet<StandardPluralCategories> set = getCanonicalSet(pr.getKeywords()); 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setsToRules.put(set, pr); 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.put(pr, locale); 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Entry<Set<StandardPluralCategories>, Set<PluralRules>> entry1 : setsToRules.keyValuesSet()) { 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<StandardPluralCategories> set = entry1.getKey(); 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<PluralRules> rules = entry1.getValue(); 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.out.println("\n // " + set); 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (PluralRules rule : rules) { 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<ULocale> locales = data.get(rule); 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.out.print(" \"" + CollectionUtilities.join(locales, ",")); 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (StandardPluralCategories spc : set) { 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = spc.toString(); 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples samples = rule.getDecimalSamples(keyword, SampleType.INTEGER); 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.out.print("; " + spc + ": " + samples); 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.out.println("\","); 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keywords 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private EnumSet<StandardPluralCategories> getCanonicalSet(Set<String> keywords) { 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumSet<StandardPluralCategories> result = EnumSet.noneOf(StandardPluralCategories.class); 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String s : keywords) { 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(StandardPluralCategories.valueOf(s)); 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final String[] LOCALE_SNAPSHOT = { 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [other] 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "bm,bo,dz,id,ig,ii,in,ja,jbo,jv,jw,kde,kea,km,ko,lkt,lo,ms,my,nqo,root,sah,ses,sg,th,to,vi,wo,yo,zh; other: @integer 0~15, 100, 1000, 10000, 100000, 1000000, …", 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, other] 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "am,bn,fa,gu,hi,kn,mr,zu; one: @integer 0, 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ff,fr,hy,kab; one: @integer 0, 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ast,ca,de,en,et,fi,fy,gl,it,ji,nl,sv,sw,ur,yi; one: @integer 1; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "pt; one: @integer 1; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "si; one: @integer 0, 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ak,bh,guw,ln,mg,nso,pa,ti,wa; one: @integer 0, 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "tzm; one: @integer 0, 1, 11~24; other: @integer 2~10, 100~106, 1000, 10000, 100000, 1000000, …", 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "af,asa,az,bem,bez,bg,brx,cgg,chr,ckb,dv,ee,el,eo,es,eu,fo,fur,gsw,ha,haw,hu,jgo,jmc,ka,kaj,kcg,kk,kkj,kl,ks,ksb,ku,ky,lb,lg,mas,mgo,ml,mn,nah,nb,nd,ne,nn,nnh,no,nr,ny,nyn,om,or,os,pap,ps,rm,rof,rwk,saq,seh,sn,so,sq,ss,ssy,st,syr,ta,te,teo,tig,tk,tn,tr,ts,ug,uz,ve,vo,vun,wae,xh,xog; one: @integer 1; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "pt_PT; one: @integer 1; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "da; one: @integer 1; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "is; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; other: @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, …", 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "mk; one: @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …; other: @integer 0, 2~10, 12~17, 100, 1000, 10000, 100000, 1000000, …", 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "fil,tl; one: @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, …; other: @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, …", 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [zero, one, other] 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "lag; zero: @integer 0; one: @integer 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "lv,prg; zero: @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, …; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; other: @integer 2~9, 22~29, 102, 1002, …", 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ksh; zero: @integer 0; one: @integer 1; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, …", 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, two, other] 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "iu,kw,naq,se,sma,smi,smj,smn,sms; one: @integer 1; two: @integer 2; other: @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, …", 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, few, other] 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "shi; one: @integer 0, 1; few: @integer 2~10; other: @integer 11~26, 100, 1000, 10000, 100000, 1000000, …", 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "mo,ro; one: @integer 1; few: @integer 0, 2~16, 101, 1001, …; other: @integer 20~35, 100, 1000, 10000, 100000, 1000000, …", 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "bs,hr,sh,sr; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; few: @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …; other: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …", 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, two, few, other] 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "gd; one: @integer 1, 11; two: @integer 2, 12; few: @integer 3~10, 13~19; other: @integer 0, 20~34, 100, 1000, 10000, 100000, 1000000, …", 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "sl; one: @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, …; two: @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, …; few: @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, …; other: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …", 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, two, many, other] 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "he,iw; one: @integer 1; two: @integer 2; many: @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, …; other: @integer 0, 3~17, 101, 1001, …", 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, few, many, other] 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "cs,sk; one: @integer 1; few: @integer 2~4; many: null; other: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …", 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "be; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; few: @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …; many: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …; other: null", 9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "lt; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; few: @integer 2~9, 22~29, 102, 1002, …; many: null; other: @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, …", 9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "mt; one: @integer 1; few: @integer 0, 2~10, 102~107, 1002, …; many: @integer 11~19, 111~117, 1011, …; other: @integer 20~35, 100, 1000, 10000, 100000, 1000000, …", 9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "pl; one: @integer 1; few: @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …; many: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …; other: null", 9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ru,uk; one: @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …; few: @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …; many: @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …; other: null", 9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [one, two, few, many, other] 10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "br; one: @integer 1, 21, 31, 41, 51, 61, 81, 101, 1001, …; two: @integer 2, 22, 32, 42, 52, 62, 82, 102, 1002, …; few: @integer 3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, …; many: @integer 1000000, …; other: @integer 0, 5~8, 10~20, 100, 1000, 10000, 100000, …", 10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ga; one: @integer 1; two: @integer 2; few: @integer 3~6; many: @integer 7~10; other: @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, …", 10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "gv; one: @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …; two: @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, …; few: @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, …; many: null; other: @integer 3~10, 13~19, 23, 103, 1003, …", 10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // [zero, one, two, few, many, other] 10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ar; zero: @integer 0; one: @integer 1; two: @integer 2; few: @integer 3~10, 103~110, 1003, …; many: @integer 11~26, 111, 1011, …; other: @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, …", 10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "cy; zero: @integer 0; one: @integer 1; two: @integer 2; few: @integer 3; many: @integer 6; other: @integer 4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, …", }; 10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private <T extends Serializable> T serializeAndDeserialize(T original, Output<Integer> size) { 10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ByteArrayOutputStream baos = new ByteArrayOutputStream(); 10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectOutputStream ostream = new ObjectOutputStream(baos); 10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ostream.writeObject(original); 10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ostream.flush(); 10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert byte bytes[] = baos.toByteArray(); 10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size.value = bytes.length; 10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert T reconstituted = (T) istream.readObject(); 10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return reconstituted; 10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IOException e) { 10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (ClassNotFoundException e) { 10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestSerialization() { 10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Output<Integer> size = new Output<Integer>(); 10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int max = 0; 10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (ULocale locale : PluralRules.getAvailableULocales()) { 10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules item = PluralRules.forLocale(locale); 10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules item2 = serializeAndDeserialize(item, size); 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln(locale + "\tsize:\t" + size.value); 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert max = Math.max(max, size.value); 10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!assertEquals(locale + "\tPlural rules before and after serialization", item, item2)) { 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for debugging 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules item3 = serializeAndDeserialize(item, size); 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert item.equals(item3); 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("max \tsize:\t" + max); 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class FixedDecimalHandler implements SerializableTest.Handler { 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object[] getTestObjects() { 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal items[] = { new FixedDecimal(3d), new FixedDecimal(3d, 2), new FixedDecimal(3.1d, 1), 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new FixedDecimal(3.1d, 2), }; 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return items; 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean hasSameBehavior(Object a, Object b) { 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal a1 = (FixedDecimal) a; 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal b1 = (FixedDecimal) b; 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return a1.equals(b1); 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void TestSerial() { 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules s = PluralRules.forLocale(ULocale.ENGLISH); 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkStreamingEquality(s); 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void checkStreamingEquality(PluralRules s) { 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOut); 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert objectOutputStream.writeObject(s); 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert objectOutputStream.close(); 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert byte[] contents = byteOut.toByteArray(); 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln(s.getClass() + ": " + showBytes(contents)); 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ByteArrayInputStream byteIn = new ByteArrayInputStream(contents); 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectInputStream objectInputStream = new ObjectInputStream(byteIn); 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object obj = objectInputStream.readObject(); 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("Streamed Object equals ", s, obj); 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertNull("TestSerial", e); 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param contents 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String showBytes(byte[] contents) { 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder b = new StringBuilder('['); 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < contents.length; ++i) { 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int item = contents[i] & 0xFF; 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item >= 0x20 && item <= 0x7F) { 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b.append((char) item); 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b.append('(').append(Utility.hex(item, 2)).append(')'); 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return b.append(']').toString(); 10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void testJavaLocaleFactory() { 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rulesU0 = PluralRules.forLocale(ULocale.FRANCE); 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rulesJ0 = PluralRules.forLocale(Locale.FRANCE); 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("forLocale()", rulesU0, rulesJ0); 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rulesU1 = PluralRules.forLocale(ULocale.FRANCE, PluralType.ORDINAL); 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rulesJ1 = PluralRules.forLocale(Locale.FRANCE, PluralType.ORDINAL); 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assertEquals("forLocale() with type", rulesU1, rulesJ1); 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 1106