From: Mark Davis Date: Mon, 19 Aug 2013 18:32:42 +0000 (+0000) Subject: ICU-8474 major change to PluralRules to move sample generation code into CLDR. Also... X-Git-Tag: milestone-59-0-1~2696 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6cfd14931404f1c7bc8d0a6c2fbf481442d35eb0;p=icu ICU-8474 major change to PluralRules to move sample generation code into CLDR. Also did close to final renaming of internal classes X-SVN-Rev: 34064 --- diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java index a0777b5e383..df2a6a3b236 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/PluralRulesTest.java @@ -34,9 +34,12 @@ import com.ibm.icu.dev.util.CollectionUtilities; import com.ibm.icu.dev.util.Relation; import com.ibm.icu.impl.Utility; import com.ibm.icu.text.PluralRules; +import com.ibm.icu.text.PluralRules.FixedDecimalRange; +import com.ibm.icu.text.PluralRules.FixedDecimalSamples; import com.ibm.icu.text.PluralRules.KeywordStatus; -import com.ibm.icu.text.PluralRules.NumberInfo; +import com.ibm.icu.text.PluralRules.FixedDecimal; import com.ibm.icu.text.PluralRules.PluralType; +import com.ibm.icu.text.PluralRules.SampleType; import com.ibm.icu.util.Output; import com.ibm.icu.util.ULocale; @@ -54,6 +57,33 @@ public class PluralRulesTest extends TestFmwk { new PluralRulesTest().run(args); } + public void testNewSamples() { + String description = "one: n is 3 or f is 5 @integer 3,19, @decimal 3.50 ~ 3.53, …; other: @decimal 99~103, 999, …"; + PluralRules test = PluralRules.createRules(description); + + checkNewSamples(description, test, "one", PluralRules.SampleType.INTEGER, "@integer 3, 19", true, new FixedDecimal(3)); + checkNewSamples(description, test, "one", PluralRules.SampleType.DECIMAL, "@decimal 3.50~3.53, …", false, new FixedDecimal(3.5,2)); + Collection oldSamples = test.getSamples("one"); + assertEquals("getSamples; " + "one" + "; " + description, new TreeSet(Arrays.asList(3d, 19d, 3.5d, 3.51d, 3.52d, 3.53d)), oldSamples); + + checkNewSamples(description, test, "other", PluralRules.SampleType.INTEGER, "", true, null); + checkNewSamples(description, test, "other", PluralRules.SampleType.DECIMAL, "@decimal 99~103, 999, …", false, new FixedDecimal(99d)); + Collection oldSamples2 = test.getSamples("other"); + assertEquals("getSamples; " + "other" + "; " + description, new TreeSet(Arrays.asList(99d, 100d, 101d, 102d, 103d, 999d)), oldSamples2); + } + + public void checkNewSamples(String description, PluralRules test, String keyword, SampleType sampleType, + String samplesString, boolean isBounded, FixedDecimal firstInRange) { + String title = description + ", " + sampleType; + FixedDecimalSamples samples = test.getDecimalSamples(keyword, sampleType); + if (samples != null) { + assertEquals("samples; " + title, samplesString, samples.toString()); + assertEquals("bounded; " + title, isBounded, samples.bounded); + assertEquals("first; " + title, firstInRange, samples.samples.iterator().next().start); + } + assertEquals("limited: " + title, isBounded, test.isLimited(keyword, sampleType)); + } + private static final String[] parseTestData = { "a: n is 1", "a:1", "a: n mod 10 is 2", "a:2,12,22", @@ -139,8 +169,8 @@ public class PluralRulesTest extends TestFmwk { private static String[][] operandTestData = { {"a: n 3", "FAIL"}, - {"a: !n!≠!1,2; b: not n is 3..5; c:n≠5", "a:1,2; b:6,7; c:3,4"}, - {"a: !n!≠!1,2; b: n!=3..5; c:n≠5", "a:1,2; b:6,7; c:3,4"}, + {"a: n=1,2; b: n != 3..5; c:n!=5", "a:1,2; b:6,7; c:3,4"}, + {"a: n=1,2; b: n!=3..5; c:n!=5", "a:1,2; b:6,7; c:3,4"}, {"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"}, {"a: i is 2; b:i is 3", @@ -171,7 +201,7 @@ public class PluralRulesTest extends TestFmwk { if (FAIL_EXPECTED) { assertNull("Should fail with 'null' return.", rules); } else { - logln(rules.toString()); + logln(rules == null ? "null rules" : rules.toString()); checkCategoriesAndExpected(pattern, categoriesAndExpected, rules); } } catch (Exception e) { @@ -187,9 +217,16 @@ public class PluralRulesTest extends TestFmwk { main: for (ULocale locale : factory.getAvailableULocales()) { PluralRules rules = factory.forLocale(locale); - Collection samples = rules.getFractionSamples(); Map keywordToRule = new HashMap(); + Collection samples = new LinkedHashSet(); + for (String keyword : rules.getKeywords()) { + for (SampleType sampleType : SampleType.values()) { + FixedDecimalSamples samples2 = rules.getDecimalSamples(keyword, sampleType); + if (samples2 != null) { + samples.add(samples2); + } + } if (keyword.equals("other")) { continue; } @@ -202,21 +239,30 @@ public class PluralRulesTest extends TestFmwk { } keywordToRule.put(keyword, singleRule); } - Map collisionTest = new TreeMap(); - for (NumberInfo sample : samples) { - collisionTest.clear(); - for (Entry entry: keywordToRule.entrySet()) { - PluralRules rule = entry.getValue(); - String foundKeyword = rule.select(sample); - if (foundKeyword.equals("other")) { - continue; - } - String old = collisionTest.get(sample); - if (old != null) { - errln(locale + "\tNon-unique rules: " + sample + " => " + old + " & " + foundKeyword); - rule.select(sample); - } else { - collisionTest.put(sample, foundKeyword); + Map collisionTest = new TreeMap(); + for (FixedDecimalSamples sample3 : samples) { + Set samples2 = sample3.getSamples(); + if (samples2 == null) { + continue; + } + for (FixedDecimalRange sample : samples2) { + for (int i = 0; i < 1; ++i) { + FixedDecimal item = i == 0 ? sample.start : sample.end; + collisionTest.clear(); + for (Entry entry: keywordToRule.entrySet()) { + PluralRules rule = entry.getValue(); + String foundKeyword = rule.select(item); + if (foundKeyword.equals("other")) { + continue; + } + String old = collisionTest.get(item); + if (old != null) { + errln(locale + "\tNon-unique rules: " + item + " => " + old + " & " + foundKeyword); + rule.select(item); + } else { + collisionTest.put(item, foundKeyword); + } + } } } } @@ -247,8 +293,10 @@ public class PluralRulesTest extends TestFmwk { private static String[][] equalityTestData = { // once we add fractions, we had to retract the "test all possibilities" for equality, // so we only have a limited set of equality tests now. - { "a:n in 2;b:n in 5", - "b: n in 5;a: n in 2;" }, + { "c: n%11!=5", "c: n mod 11 is not 5" }, + { "c: n not is 7", "c: n != 7" }, + { "a:n in 2;", "a: n = 2" }, + { "b:n not in 5;", "b: n not = 5" }, // { "a: n is 5", // "a: n in 2..6 and n not in 2..4 and n is not 6" }, @@ -278,7 +326,7 @@ public class PluralRulesTest extends TestFmwk { int start = shouldBeEqual ? i : i + 1; for (int j = start; j < objects.length; ++j) { Object rhs = objects[j]; - if (shouldBeEqual != lhs.equals(rhs)) { + if (rhs == null || shouldBeEqual != lhs.equals(rhs)) { String msg = shouldBeEqual ? "should be equal" : "should not be equal"; fail(id + " " + msg + " (" + i + ", " + j + "):\n " + lhs + "\n " + rhs); } @@ -415,9 +463,10 @@ public class PluralRulesTest extends TestFmwk { * Tests getUniqueKeywordValue() */ public void TestGetUniqueKeywordValue() { + assertRuleKeyValue("a: n is 1", "not_defined", PluralRules.NO_UNIQUE_VALUE); // key not defined + assertRuleValue("n within 2..2", 2); assertRuleValue("n is 1", 1); assertRuleValue("n in 2..2", 2); - assertRuleValue("n within 2..2", 2); assertRuleValue("n in 3..4", PluralRules.NO_UNIQUE_VALUE); assertRuleValue("n within 3..4", PluralRules.NO_UNIQUE_VALUE); assertRuleValue("n is 2 or n is 2", 2); @@ -426,7 +475,6 @@ public class PluralRulesTest extends TestFmwk { assertRuleValue("n is 2 and n is 3", PluralRules.NO_UNIQUE_VALUE); assertRuleValue("n is 2 or n in 2..3", PluralRules.NO_UNIQUE_VALUE); assertRuleValue("n is 2 and n in 2..3", 2); - assertRuleKeyValue("a: n is 1", "not_defined", PluralRules.NO_UNIQUE_VALUE); // key not defined assertRuleKeyValue("a: n is 1", "other", PluralRules.NO_UNIQUE_VALUE); // key matches default rule assertRuleValue("n in 2,3", PluralRules.NO_UNIQUE_VALUE); assertRuleValue("n in 2,3..6 and n not in 2..3,5..6", 4); @@ -449,12 +497,18 @@ public class PluralRulesTest extends TestFmwk { Collection list = rules.getSamples(keyword); logln("keyword: " + keyword + ", samples: " + list); - assertNotNull("list is not null", list); + assertNotNull("keyword: " + keyword + ", rules: " + rules + ": list is not null", list); if (list != null) { - assertTrue("list is not empty", !list.isEmpty()); - - for (double value : list) { - assertEquals("value " + value + " matches keyword", keyword, rules.select(value)); + if (!assertTrue(locale + "Testing getSamples.isEmpty for " + keyword + ", in " + rules.getRules(keyword), !list.isEmpty())) { + int debugHere = 0; + rules.getSamples(keyword); + } + if (rules.toString().contains(": j")) { + // hack until we remove j + } else { + for (double value : list) { + assertEquals(locale + " value " + value + " matching keyword", keyword, rules.select(value)); + } } } } @@ -470,30 +524,33 @@ public class PluralRulesTest extends TestFmwk { public void TestGetAllKeywordValues() { // data is pairs of strings, the rule, and the expected values as arguments String[] data = { - "a: n in 2..5", "a: 2,3,4,5; other: null; b:", + "a: n mod 3 is 0", "a: null", + "a: n in 2..5 and n within 5..8", "a: 5", + "a: n in 2..5", "a: 2,3,4,5; other: null", "a: n not in 2..5", "a: null; other: null", "a: n within 2..5", "a: null; other: null", "a: n not within 2..5", "a: null; other: null", "a: n in 2..5 or n within 6..8", "a: null", // ignore 'other' here on out, always null "a: n in 2..5 and n within 6..8", "a:", - "a: n in 2..5 and n within 5..8", "a: 5", - "a: n within 2..5 and n within 6..8", "a:", // our sampling catches these - "a: n within 2..5 and n within 5..8", "a: 5", // '' - "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5", "a: 2,4", - "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", "a: null", // but not this... - "a: n mod 3 is 0", "a: null", - "a: n mod 3 is 0 and n within 1..2", "a:", - "a: n mod 3 is 0 and n within 0..5", "a: 0,3", - "a: n mod 3 is 0 and n within 0..6", "a: null", // similarly with mod, we don't catch... - "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", + // we no longer support 'degenerate' rules + // "a: n within 2..5 and n within 6..8", "a:", // our sampling catches these + // "a: n within 2..5 and n within 5..8", "a: 5", // '' + // "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5", "a: 2,4", + // "a: n mod 3 is 0 and n within 0..5", "a: 0,3", + "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", "a: null", // but not this... + "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: null", // similarly with mod, we don't catch... + "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", }; for (int i = 0; i < data.length; i += 2) { String ruleDescription = data[i]; String result = data[i+1]; PluralRules p = PluralRules.createRules(ruleDescription); + if (p == null) { // for debugging + PluralRules.createRules(ruleDescription); + } for (String ruleResult : result.split(";")) { String[] ruleAndValues = ruleResult.split(":"); String keyword = ruleAndValues[0].trim(); @@ -503,18 +560,18 @@ public class PluralRulesTest extends TestFmwk { } Collection values; if (valueList == null || valueList.length() == 0) { - values = Collections.emptyList(); + values = Collections.EMPTY_SET; } else if ("null".equals(valueList)) { values = null; } else { - values = new ArrayList(); + values = new TreeSet(); for (String value : valueList.split(",")) { values.add(Double.parseDouble(value)); } } Collection results = p.getAllKeywordValues(keyword); - assertEquals("keyword '" + keyword + "'", values, results); + assertEquals(keyword + " in " + ruleDescription, values, results); if (results != null) { try { @@ -662,8 +719,9 @@ public class PluralRulesTest extends TestFmwk { Set locales = data.get(rule); System.out.print(" \"" + CollectionUtilities.join(locales, ",")); for (StandardPluralCategories spc : set) { - Collection samples = rule.getFractionSamples(spc.toString()); - System.out.print("; " + spc + ": " + CollectionUtilities.join(samples, ", ")); + String keyword = spc.toString(); + FixedDecimalSamples samples = rule.getDecimalSamples(keyword, SampleType.INTEGER); + System.out.print("; " + spc + ": " + samples); } System.out.println("\","); }