1 package org.unicode.cldr.unittest;
2 
3 import com.google.common.collect.ImmutableList;
4 import com.google.common.collect.ImmutableMap;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.Set;
13 import java.util.TreeSet;
14 import org.unicode.cldr.test.CheckCLDR.CheckStatus;
15 import org.unicode.cldr.test.CheckCLDR.Options;
16 import org.unicode.cldr.test.CheckDisplayCollisions;
17 import org.unicode.cldr.util.CLDRConfig;
18 import org.unicode.cldr.util.CLDRFile;
19 import org.unicode.cldr.util.SimpleXMLSource;
20 import org.unicode.cldr.util.XMLSource;
21 
22 public class TestCheckDisplayCollisions extends TestFmwkPlus {
23     private static final String ukRegion =
24             "//ldml/localeDisplayNames/territories/territory[@type=\"GB\"]";
25     private static final String englandSubdivision =
26             "//ldml/localeDisplayNames/subdivisions/subdivision[@type=\"gbeng\"]";
27 
28     private static final String scorpioEmoji =
29             "//ldml/annotations/annotation[@cp=\"♏\"][@type=\"tts\"]";
30     private static final String scorpionEmoji =
31             "//ldml/annotations/annotation[@cp=\"��\"][@type=\"tts\"]";
32 
33     private static final String japanRegion =
34             "//ldml/localeDisplayNames/territories/territory[@type=\"JP\"]";
35     private static final String japanMap =
36             "//ldml/annotations/annotation[@cp=\"��\"][@type=\"tts\"]";
37 
38     private static final String milli =
39             "//ldml/units/unitLength[@type=\"short\"]/compoundUnit[@type=\"10p-3\"]/unitPrefixPattern";
40     private static final String mega =
41             "//ldml/units/unitLength[@type=\"short\"]/compoundUnit[@type=\"10p6\"]/unitPrefixPattern";
42 
43     private static final String deciLong =
44             "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"10p-1\"]/unitPrefixPattern";
45     private static final String deciNarrow =
46             "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"10p-1\"]/unitPrefixPattern";
47     private static final String deciShort =
48             "//ldml/units/unitLength[@type=\"short\"]/compoundUnit[@type=\"10p-1\"]/unitPrefixPattern";
49 
main(String[] args)50     public static void main(String[] args) {
51         new TestCheckDisplayCollisions().run(args);
52     }
53 
testInheritance()54     public void testInheritance() {
55         XMLSource rootSource = new SimpleXMLSource("root");
56         CLDRFile root = new CLDRFile(rootSource);
57 
58         XMLSource enSource = new SimpleXMLSource("en");
59         CLDRFile en = new CLDRFile(enSource);
60 
61         XMLSource frSource = new SimpleXMLSource("fr");
62         frSource.putValueAtPath(scorpionEmoji, "scorpion");
63         frSource.putValueAtPath(scorpioEmoji, "scorpion zodiac");
64         frSource.putValueAtPath(englandSubdivision, "Angleterre");
65         frSource.putValueAtPath(ukRegion, "Royaume-Uni");
66         frSource.putValueAtDPath(japanRegion, "Japon");
67         frSource.putValueAtDPath(japanMap, "carte du Japon");
68         frSource.putValueAtDPath(milli, "m{0}");
69         frSource.putValueAtDPath(mega, "M{0}");
70 
71         frSource.putValueAtDPath(deciLong, "d{0}");
72         frSource.putValueAtDPath(deciNarrow, "d{0}");
73         frSource.putValueAtDPath(deciShort, "d{0}");
74 
75         CLDRFile fr = new CLDRFile(frSource);
76 
77         XMLSource frCaSource = new SimpleXMLSource("fr_CA");
78         frCaSource.putValueAtPath(scorpioEmoji, "scorpion");
79         frCaSource.putValueAtPath(ukRegion, "Angleterre");
80         frCaSource.putValueAtDPath(japanMap, "Japon");
81         CLDRFile frCA = new CLDRFile(frCaSource);
82 
83         TestFactory factory = new TestFactory();
84         factory.addFile(root);
85         factory.addFile(en);
86         factory.addFile(fr);
87         factory.addFile(frCA);
88 
89         CheckDisplayCollisions cdc = new CheckDisplayCollisions(factory);
90         cdc.setEnglishFile(CLDRConfig.getInstance().getEnglish());
91 
92         CLDRFile frResolved = factory.make("fr", true);
93         checkFile(cdc, fr, frResolved);
94 
95         CLDRFile frCaResolved = factory.make("fr_CA", true);
96         checkFile(cdc, frCA, frCaResolved, scorpioEmoji, ukRegion);
97     }
98 
testUnitPatternCollisions()99     public void testUnitPatternCollisions() {
100         final String unitPattern1 =
101                 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-dot\"]/unitPattern[@count=\"one\"]";
102         /** different count as # 1. MUST NOT COLLIDE WITH #1 */
103         final String unitPattern2 =
104                 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-dot\"]/unitPattern[@count=\"other\"]";
105         /** different unit as # 1. MUST COLLIDE WITH #1 */
106         final String unitPattern3 =
107                 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-point\"]/unitPattern[@count=\"one\"]";
108         /**
109          * #4 and #5 must NOT collide; case="nominative" and case="accusative" when paths are
110          * otherwise identical and have the same value
111          */
112         final String unitPattern4 =
113                 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"volume-dram\"]/unitPattern[@count=\"other\"][@case=\"nominative\"]";
114         final String unitPattern5 =
115                 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"volume-dram\"]/unitPattern[@count=\"other\"][@case=\"accusative\"]";
116 
117         mustCollide(false, unitPattern1, unitPattern2);
118         mustCollide(true, unitPattern1, unitPattern3);
119         mustCollide(false, unitPattern4, unitPattern5);
120     }
121 
mustCollide( boolean expectCollisionErrors, String unitPatternA, String unitPatternB)122     private void mustCollide(
123             boolean expectCollisionErrors, String unitPatternA, String unitPatternB) {
124         final String testLocale = "pt";
125         final String duplicatedValue = "{0}pontos";
126 
127         final XMLSource rootSource = new SimpleXMLSource("root");
128         final CLDRFile root = new CLDRFile(rootSource);
129 
130         final XMLSource enSource = new SimpleXMLSource("en");
131         final CLDRFile en = new CLDRFile(enSource);
132 
133         final XMLSource source = new SimpleXMLSource(testLocale);
134 
135         source.putValueAtPath(unitPatternA, duplicatedValue);
136         source.putValueAtPath(unitPatternB, duplicatedValue);
137 
138         CLDRFile file = new CLDRFile(source);
139 
140         TestFactory factory = new TestFactory();
141         factory.addFile(root);
142         factory.addFile(en);
143         factory.addFile(file);
144 
145         CheckDisplayCollisions cdc = new CheckDisplayCollisions(factory);
146         cdc.setEnglishFile(CLDRConfig.getInstance().getEnglish());
147 
148         CLDRFile ptResolved = factory.make(testLocale, true);
149         if (expectCollisionErrors) {
150             checkFile(cdc, file, ptResolved, unitPatternA, unitPatternB);
151         } else {
152             checkFile(cdc, file, ptResolved);
153         }
154     }
155 
checkFile( CheckDisplayCollisions cdc, CLDRFile cldrFile, CLDRFile cldrFileResolved, String... expectedErrors)156     private void checkFile(
157             CheckDisplayCollisions cdc,
158             CLDRFile cldrFile,
159             CLDRFile cldrFileResolved,
160             String... expectedErrors) {
161         List<CheckStatus> possibleErrors = new ArrayList<>();
162         Options options = new Options();
163         cdc.setCldrFileToCheck(cldrFile, options, possibleErrors);
164         if (!possibleErrors.isEmpty()) {
165             errln("init: " + possibleErrors);
166             possibleErrors.clear();
167         }
168         Map<String, List<CheckStatus>> found = new HashMap<>();
169         for (String path : cldrFileResolved) {
170             String value = cldrFileResolved.getStringValue(path);
171             // System.out.println(path + "\t" + value);
172             if (path.equals(deciLong)) {
173                 int debug = 0;
174             }
175             cdc.check(path, path, value, options, possibleErrors);
176             if (!possibleErrors.isEmpty()) {
177                 found.put(path, ImmutableList.copyOf(possibleErrors));
178                 possibleErrors.clear();
179                 logln("Found error " + cldrFile.getLocaleID() + ":\t" + path + ", " + value);
180             } else {
181                 logln("No error " + cldrFile.getLocaleID() + ":\t" + path + ", " + value);
182             }
183         }
184         Set<String> expected = new TreeSet<>(Arrays.asList(expectedErrors));
185         for (Entry<String, List<CheckStatus>> entry : found.entrySet()) {
186             String path = entry.getKey();
187             if (expected.contains(path)) {
188                 expected.remove(path);
189             } else {
190                 errln(
191                         cldrFile.getLocaleID()
192                                 + " unexpected error: "
193                                 + path
194                                 + " : "
195                                 + entry.getValue());
196             }
197             checkUnknown(path, entry);
198         }
199         assertEquals(
200                 cldrFile.getLocaleID() + " expected to be errors: ",
201                 Collections.emptySet(),
202                 expected);
203     }
204 
205     /**
206      * Report an error if the CheckStatus parameters contain the word "Unknown", which can be a
207      * symptom of errors such as removal of required "count" attribute. "Unknown" may not always be
208      * an error, but for the data used in this test we don't expect it.
209      *
210      * @param path
211      * @param entry
212      */
checkUnknown(String path, Entry<String, List<CheckStatus>> entry)213     private void checkUnknown(String path, Entry<String, List<CheckStatus>> entry) {
214         CheckStatus cs = entry.getValue().get(0);
215         String s = cs.getParameters()[0].toString();
216         if (s.contains("Unknown")) {
217             errln("Found Unknown in : " + path + ":\n" + s);
218         }
219     }
220 
TestDotPixel14031()221     public void TestDotPixel14031() {
222         Map<String, String> pathValuePairs =
223                 ImmutableMap.of(
224                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-dot\"]/displayName",
225                                 "Punkt",
226                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-pixel\"]/displayName",
227                                 "Punkt",
228                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-pixel-per-centimeter\"]/displayName",
229                                 "Punkt pro Zentimeter",
230                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-dot-per-centimeter\"]/displayName",
231                                 "Punkt pro Zentimeter");
232         TestFactory factory = makeFakeCldrFile("de", pathValuePairs);
233         checkDisplayCollisions("de", pathValuePairs, factory);
234     }
235 
checkDisplayCollisions( String locale, Map<String, String> pathValuePairs, TestFactory factory)236     public void checkDisplayCollisions(
237             String locale, Map<String, String> pathValuePairs, TestFactory factory) {
238         CheckDisplayCollisions cdc = new CheckDisplayCollisions(factory);
239         cdc.setEnglishFile(CLDRConfig.getInstance().getEnglish());
240 
241         List<CheckStatus> possibleErrors = new ArrayList<>();
242         cdc.setCldrFileToCheck(
243                 factory.make(locale, true), new Options(ImmutableMap.of()), possibleErrors);
244         for (Entry<String, String> entry : pathValuePairs.entrySet()) {
245             cdc.check(
246                     entry.getKey(),
247                     entry.getKey(),
248                     entry.getValue(),
249                     new Options(ImmutableMap.of()),
250                     possibleErrors);
251             assertEquals(entry.toString(), Collections.emptyList(), possibleErrors);
252         }
253     }
254 
makeFakeCldrFile(String locale, Map<String, String> pathValuePairs)255     public TestFactory makeFakeCldrFile(String locale, Map<String, String> pathValuePairs) {
256         TestFactory factory = new TestFactory();
257         XMLSource rootSource = new SimpleXMLSource("root");
258         factory.addFile(new CLDRFile(rootSource));
259 
260         XMLSource localeSource = new SimpleXMLSource(locale);
261         for (Entry<String, String> entry : pathValuePairs.entrySet()) {
262             localeSource.putValueAtPath(entry.getKey(), entry.getValue());
263         }
264         factory.addFile(new CLDRFile(localeSource));
265         return factory;
266     }
267 
TestDurationPersonVariants()268     public void TestDurationPersonVariants() {
269         Map<String, String> pathValuePairs =
270                 ImmutableMap.of(
271                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"duration-day-person\"]/unitPattern[@count=\"other\"]",
272                                 "Punkt",
273                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"duration-day\"]/unitPattern[@count=\"other\"]",
274                                 "Punkt",
275                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-pixel\"]/displayName",
276                                 "Punkt",
277                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-pixel-per-centimeter\"]/displayName",
278                                 "Punkt pro Zentimeter",
279                         "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"graphics-dot-per-centimeter\"]/displayName",
280                                 "Punkt pro Zentimeter");
281         TestFactory factory = makeFakeCldrFile("de", pathValuePairs);
282         checkDisplayCollisions("de", pathValuePairs, factory);
283     }
284 }
285