1 // © 2019 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 package org.unicode.icu.tool.cldrtoicu.mapper; 4 5 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.AFTERNOON1; 6 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.EVENING1; 7 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.MIDNIGHT; 8 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.MORNING1; 9 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.NIGHT1; 10 import static org.unicode.icu.tool.cldrtoicu.mapper.DayPeriodsMapperTest.RuleType.NOON; 11 import static org.unicode.icu.tool.cldrtoicu.testing.IcuDataSubjectFactory.assertThat; 12 13 import java.util.Arrays; 14 import java.util.Map; 15 import java.util.Set; 16 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 import org.junit.runners.JUnit4; 20 import org.unicode.cldr.api.CldrData; 21 import org.unicode.cldr.api.CldrDataSupplier; 22 import org.unicode.cldr.api.CldrValue; 23 import org.unicode.icu.tool.cldrtoicu.IcuData; 24 25 import com.google.common.base.Ascii; 26 import com.google.common.base.Joiner; 27 import com.google.common.collect.ImmutableMap; 28 import com.google.common.collect.ImmutableSet; 29 30 @RunWith(JUnit4.class) 31 public class DayPeriodsMapperTest { 32 // A subset of rule types for testing. 33 enum RuleType { 34 MORNING1, NOON, AFTERNOON1, EVENING1, NIGHT1, MIDNIGHT; 35 toString()36 @Override public String toString() { 37 return Ascii.toLowerCase(name()); 38 } 39 } 40 41 // Possible rule names (these are the value attributes). 42 enum RuleName { 43 AT, BEFORE, FROM; 44 toString()45 @Override public String toString() { 46 return Ascii.toLowerCase(name()); 47 } 48 } 49 50 @Test testSimple()51 public void testSimple() { 52 Set<String> locales = ImmutableSet.of("en_GB", "en_AU", "en_NZ"); 53 CldrData cldrData = cldrData( 54 dayPeriodRule(locales, MORNING1, isBetween("04:00", "12:00")), 55 dayPeriodRule(locales, NOON, isAt("12:00")), 56 dayPeriodRule(locales, AFTERNOON1, isBetween("12:00", "18:00")), 57 dayPeriodRule(locales, EVENING1, isBetween("18:00", "21:00")), 58 dayPeriodRule(locales, NIGHT1, isBetween("21:00", "04:00")), 59 dayPeriodRule(locales, MIDNIGHT, isAt("00:00"))); 60 61 IcuData icuData = DayPeriodsMapper.process(cldrData); 62 63 assertThat(icuData).hasName("dayPeriods"); 64 assertThat(icuData).hasFallback(false); 65 assertThat(icuData).hasValuesFor("/locales/en_AU", "set1"); 66 assertThat(icuData).hasValuesFor("/locales/en_GB", "set1"); 67 assertThat(icuData).hasValuesFor("/locales/en_NZ", "set1"); 68 69 assertThat(icuData).hasValuesFor("/rules/set1/morning1/from", "04:00"); 70 assertThat(icuData).hasValuesFor("/rules/set1/morning1/before", "12:00"); 71 assertThat(icuData).hasValuesFor("/rules/set1/noon/at", "12:00"); 72 assertThat(icuData).hasValuesFor("/rules/set1/afternoon1/from", "12:00"); 73 assertThat(icuData).hasValuesFor("/rules/set1/afternoon1/before", "18:00"); 74 assertThat(icuData).hasValuesFor("/rules/set1/evening1/from", "18:00"); 75 assertThat(icuData).hasValuesFor("/rules/set1/evening1/before", "21:00"); 76 assertThat(icuData).hasValuesFor("/rules/set1/night1/from", "21:00"); 77 assertThat(icuData).hasValuesFor("/rules/set1/night1/before", "04:00"); 78 assertThat(icuData).hasValuesFor("/rules/set1/midnight/at", "00:00"); 79 } 80 81 @Test testMultipleRuleSets()82 public void testMultipleRuleSets() { 83 Set<String> locales1 = ImmutableSet.of("en_GB"); 84 Set<String> locales2 = ImmutableSet.of("en_AU", "en_NZ"); 85 CldrData cldrData = cldrData( 86 dayPeriodRule(locales1, MORNING1, isBetween("04:00", "12:00")), 87 dayPeriodRule(locales1, NOON, isAt("12:00")), 88 dayPeriodRule(locales2, MORNING1, isBetween("06:00", "13:00")), 89 dayPeriodRule(locales2, NOON, isAt("13:00"))); 90 91 IcuData icuData = DayPeriodsMapper.process(cldrData); 92 93 // This reversal of the set ordering (as compared to the order of the input paths) is 94 // because visitation requires nested path ordering, which is achieved by lexicographical 95 // ordering of path strings ("en_AU" < "en_GB"). This is an implementation detail however 96 // and might one day change. If this were switched to use DTD order, then it would be 97 // stable (but also affect the ordering of paths in the released ICU data). 98 assertThat(icuData).hasValuesFor("/locales/en_AU", "set1"); 99 assertThat(icuData).hasValuesFor("/locales/en_NZ", "set1"); 100 assertThat(icuData).hasValuesFor("/rules/set1/morning1/from", "06:00"); 101 assertThat(icuData).hasValuesFor("/rules/set1/morning1/before", "13:00"); 102 assertThat(icuData).hasValuesFor("/rules/set1/noon/at", "13:00"); 103 104 assertThat(icuData).hasValuesFor("/locales/en_GB", "set2"); 105 assertThat(icuData).hasValuesFor("/rules/set2/morning1/from", "04:00"); 106 assertThat(icuData).hasValuesFor("/rules/set2/morning1/before", "12:00"); 107 assertThat(icuData).hasValuesFor("/rules/set2/noon/at", "12:00"); 108 } 109 110 @Test testRulesetLabels()111 public void testRulesetLabels() { 112 Set<String> locales = ImmutableSet.of("en_GB"); 113 // Note that there's an implicit assumption in the mapper that the ruleset label is the 114 // same for all of the rules of any given locale (since it comes from the parent element). 115 CldrData cldrData = cldrData( 116 dayPeriodRule(locales, MORNING1, isBetween("04:00", "12:00"), "foo"), 117 dayPeriodRule(locales, NOON, isAt("12:00"), "foo")); 118 119 IcuData icuData = DayPeriodsMapper.process(cldrData); 120 121 assertThat(icuData).hasValuesFor("/locales_foo/en_GB", "set1"); 122 assertThat(icuData).hasValuesFor("/rules/set1/morning1/from", "04:00"); 123 assertThat(icuData).hasValuesFor("/rules/set1/morning1/before", "12:00"); 124 assertThat(icuData).hasValuesFor("/rules/set1/noon/at", "12:00"); 125 } 126 127 // Just demonstrating that the mapper does no data validation. 128 @Test testNoDataValidation()129 public void testNoDataValidation() { 130 Set<String> locales = ImmutableSet.of("foo", "bar"); 131 CldrData cldrData = cldrData( 132 dayPeriodRule(locales, MORNING1, isBetween("start", "end")), 133 dayPeriodRule(locales, NOON, isAt("moment"))); 134 135 IcuData icuData = DayPeriodsMapper.process(cldrData); 136 137 // This reversal of the set ordering (as compared to the order of the input paths) is 138 // because visitation requires nested path ordering, which is achieved by lexicographical 139 // ordering of path strings. This is an implementation detail however and might one day 140 // change. If this were switched to use DTD order, then it would be stable (but also 141 // affect the ordering of paths in the released ICU data). 142 assertThat(icuData).hasValuesFor("/locales/foo", "set1"); 143 assertThat(icuData).hasValuesFor("/locales/bar", "set1"); 144 assertThat(icuData).hasValuesFor("/rules/set1/morning1/from", "start"); 145 assertThat(icuData).hasValuesFor("/rules/set1/morning1/before", "end"); 146 assertThat(icuData).hasValuesFor("/rules/set1/noon/at", "moment"); 147 } 148 cldrData(CldrValue... values)149 private static CldrData cldrData(CldrValue... values) { 150 return CldrDataSupplier.forValues(Arrays.asList(values)); 151 } 152 dayPeriodRule( Set<String> locales, RuleType type, Map<RuleName, String> rules)153 private static CldrValue dayPeriodRule( 154 Set<String> locales, RuleType type, Map<RuleName, String> rules) { 155 156 return dayPeriodRule(locales, type, rules, null); 157 } 158 dayPeriodRule( Set<String> locales, RuleType type, Map<RuleName, String> rules, String label)159 private static CldrValue dayPeriodRule( 160 Set<String> locales, RuleType type, Map<RuleName, String> rules, String label) { 161 162 StringBuilder cldrPath = new StringBuilder("//supplementalData/dayPeriodRuleSet"); 163 if (label != null) { 164 appendAttribute(cldrPath, "type", label); 165 } 166 appendAttribute(cldrPath.append("/dayPeriodRules"), "locales", Joiner.on(' ').join(locales)); 167 appendAttribute(cldrPath.append("/dayPeriodRule"), "type", type); 168 rules.forEach((k, v) -> cldrPath.append(String.format("[@%s=\"%s\"]", k, v))); 169 return CldrValue.parseValue(cldrPath.toString(), ""); 170 } 171 isAt(String time)172 private static Map<RuleName, String> isAt(String time) { 173 return ImmutableMap.of(RuleName.AT, time); 174 } 175 isBetween(String from, String to)176 private static Map<RuleName, String> isBetween(String from, String to) { 177 return ImmutableMap.of(RuleName.FROM, from, RuleName.BEFORE, to); 178 } 179 appendAttribute(StringBuilder out, String k, Object v)180 private static void appendAttribute(StringBuilder out, String k, Object v) { 181 out.append(String.format("[@%s=\"%s\"]", k, v)); 182 } 183 }