1 package org.unicode.cldr.unittest; 2 3 import com.google.common.collect.ImmutableMap; 4 import com.google.common.collect.Ordering; 5 import com.ibm.icu.impl.Relation; 6 import com.ibm.icu.impl.UnicodeMap; 7 import com.ibm.icu.impl.Utility; 8 import com.ibm.icu.lang.UCharacter; 9 import com.ibm.icu.lang.UProperty; 10 import com.ibm.icu.text.Collator; 11 import com.ibm.icu.text.UnicodeSet; 12 import com.ibm.icu.util.ULocale; 13 import java.io.StringWriter; 14 import java.text.NumberFormat; 15 import java.util.ArrayList; 16 import java.util.Arrays; 17 import java.util.Collections; 18 import java.util.Comparator; 19 import java.util.HashMap; 20 import java.util.HashSet; 21 import java.util.LinkedHashSet; 22 import java.util.List; 23 import java.util.Map; 24 import java.util.Map.Entry; 25 import java.util.Random; 26 import java.util.Set; 27 import java.util.TreeMap; 28 import java.util.TreeSet; 29 import java.util.regex.Matcher; 30 import org.unicode.cldr.test.SubmissionLocales; 31 import org.unicode.cldr.tool.ConvertLanguageData.InverseComparator; 32 import org.unicode.cldr.util.*; 33 import org.unicode.cldr.util.PathHeader.PageId; 34 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count; 35 import org.unicode.cldr.util.VettingViewer.MissingStatus; 36 import org.unicode.cldr.util.VoteResolver.Level; 37 import org.unicode.cldr.util.VoteResolver.Status; 38 import org.unicode.cldr.util.VoteResolver.VoteStatus; 39 import org.unicode.cldr.util.VoteResolver.VoterInfo; 40 import org.unicode.cldr.util.props.ICUPropertyFactory; 41 42 public class TestHelper extends TestFmwkPlus { 43 public static boolean DEBUG = true; 44 45 private static final UnicodeSet DIGITS = new UnicodeSet("[0-9]"); 46 static CLDRConfig testInfo = CLDRConfig.getInstance(); 47 private static final SupplementalDataInfo SUPPLEMENTAL_DATA_INFO = 48 testInfo.getSupplementalDataInfo(); 49 private static final int STRING_ID_TEST_COUNT = 1024 * 16; 50 51 final int ONE_VETTER_BAR = Level.vetter.getVotes(Organization.unaffiliated); 52 final int TWO_VETTER_BAR = VoteResolver.LOWER_BAR; 53 main(String[] args)54 public static void main(String[] args) { 55 new TestHelper().run(args); 56 } 57 TestPluralSamples()58 public void TestPluralSamples() { 59 checkPluralSamples("en"); 60 checkPluralSamples("cs"); 61 checkPluralSamples("ar"); 62 } 63 checkPluralSamples(String locale)64 private void checkPluralSamples(String locale) { 65 PluralSamples pluralSamples = PluralSamples.getInstance(locale); 66 Set<Count> counts = SUPPLEMENTAL_DATA_INFO.getPlurals(locale).getCounts(); 67 for (int i = 1; i < 5; ++i) { 68 Map<Count, Double> samplesForDigits = pluralSamples.getSamples(i); 69 if (!counts.containsAll(samplesForDigits.keySet())) { 70 errln( 71 locale 72 + ": mismatch in samples, expected " 73 + counts 74 + ", got: " 75 + samplesForDigits); 76 } else if (samplesForDigits.size() == 0) { 77 errln(locale + ": no sample for digit " + i); 78 } else { 79 logln(locale + " plural samples: " + samplesForDigits); 80 } 81 } 82 } 83 84 public static class StringIdException extends RuntimeException { 85 private static final long serialVersionUID = 1L; 86 } 87 88 public class StringIdThread extends Thread { 89 private final Random r = new Random(); 90 private final int id; 91 StringIdThread(int i)92 StringIdThread(int i) { 93 super("Demo Thread"); 94 id = i; 95 } 96 97 @Override run()98 public void run() { 99 logln("Starting thread: " + this); 100 for (int i = 0; i < STRING_ID_TEST_COUNT; ++i) { 101 String s = String.valueOf(r.nextInt()); 102 long l = StringId.getId(s); 103 String s2 = StringId.getStringFromId(l); 104 if (!s.equals(s2)) { 105 throw new StringIdException(); 106 } 107 } 108 logln("Ending thread: " + this); 109 } 110 111 @Override toString()112 public String toString() { 113 return "StringIdThread " + id; 114 } 115 } 116 TestStringId()117 public void TestStringId() { 118 ArrayList<StringIdThread> threads = new ArrayList<>(); 119 120 for (int i = 0; i < 8; i++) { 121 StringIdThread thread = new StringIdThread(i); 122 threads.add(thread); 123 thread.start(); 124 } 125 for (StringIdThread thread : threads) { 126 try { 127 thread.join(); 128 } catch (InterruptedException e) { 129 errln(e.toString()); 130 } 131 } 132 } 133 TestUrlEscape()134 public void TestUrlEscape() { 135 Matcher byte1 = PatternCache.get("%[A-Za-z0-9]{2}").matcher(""); 136 Matcher byte2 = PatternCache.get("%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}").matcher(""); 137 Matcher byte3 = 138 PatternCache.get("%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}").matcher(""); 139 Matcher byte4 = 140 PatternCache.get("%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}%[A-Za-z0-9]{2}") 141 .matcher(""); 142 for (int i = 1; i <= 0x10FFFF; i = i * 3 / 2 + 1) { 143 String escaped = 144 EscapingUtilities.urlEscape(new StringBuilder().appendCodePoint(i).toString()); 145 logln(Integer.toHexString(i) + " => " + escaped); 146 if (EscapingUtilities.OK_TO_NOT_QUOTE.contains(i)) { 147 assertTrue("Should be unquoted", escaped.length() == 1); 148 } else if (i < 0x80) { 149 assertTrue("Should be %xx", byte1.reset(escaped).matches()); 150 } else if (i < 0x800) { 151 assertTrue("Should be %xx%xx", byte2.reset(escaped).matches()); 152 } else if (i < 0x10000) { 153 assertTrue("Should be %xx%xx%xx", byte3.reset(escaped).matches()); 154 } else { 155 assertTrue("Should be %xx%xx%xx%xx", byte4.reset(escaped).matches()); 156 } 157 } 158 } 159 TestDelegatingIterator()160 public void TestDelegatingIterator() { 161 Set<String> s = new TreeSet<>(Arrays.asList(new String[] {"a", "b", "c"})); 162 Set<String> t = new LinkedHashSet<>(Arrays.asList(new String[] {"f", "d", "e"})); 163 StringBuilder result = new StringBuilder(); 164 165 for (String u : DelegatingIterator.iterable(s, t)) { 166 result.append(u); 167 } 168 assertEquals("Iterator", "abcfde", result.toString()); 169 170 result.setLength(0); 171 for (String u : DelegatingIterator.array("s", "t", "u")) { 172 result.append(u); 173 } 174 assertEquals("Iterator", "stu", result.toString()); 175 176 int count = 0; 177 result.setLength(0); 178 for (int u : DelegatingIterator.array(1, 3, 5)) { 179 count += u; 180 } 181 assertEquals("Iterator", 9, count); 182 183 result.setLength(0); 184 for (Object u : DelegatingIterator.array(1, "t", "u", new UnicodeSet("[a-z]"))) { 185 result.append(u); 186 } 187 assertEquals("Iterator", "1tu[a-z]", result.toString()); 188 } 189 TestUntimedCounter()190 public void TestUntimedCounter() { 191 // simulates how Counter is used in VettingViewer 192 Counter<NotificationCategory> problemCounter = new Counter<>(); 193 problemCounter.increment(NotificationCategory.error); 194 problemCounter.increment(NotificationCategory.error); 195 problemCounter.increment(NotificationCategory.warning); 196 197 assertEquals("problemCounter error", 2, problemCounter.get(NotificationCategory.error)); 198 assertEquals("problemCounter warning", 1, problemCounter.get(NotificationCategory.warning)); 199 assertEquals("problemCounter weLost", 0, problemCounter.get(NotificationCategory.weLost)); 200 201 Counter<NotificationCategory> otherCounter = new Counter<>(); 202 otherCounter.addAll(problemCounter); 203 otherCounter.increment(NotificationCategory.error); 204 205 assertEquals("otherCounter error", 3, otherCounter.get(NotificationCategory.error)); 206 assertEquals("otherCounter warning", 1, otherCounter.get(NotificationCategory.warning)); 207 assertEquals("otherCounter weLost", 0, otherCounter.get(NotificationCategory.weLost)); 208 } 209 TestCounter()210 public void TestCounter() { 211 Counter<String> counter = new Counter<>(true); 212 Comparator<String> uca = 213 new Comparator<>() { 214 Collator col = Collator.getInstance(ULocale.ENGLISH); 215 216 @Override 217 public int compare(String o1, String o2) { 218 return col.compare(o1, o2); 219 } 220 }; 221 InverseComparator ucaDown = new InverseComparator(uca); 222 223 counter.add("c", 95); 224 counter.add("b", 50); 225 counter.add("b", 101); 226 counter.add("a", 100); 227 counter.add("a", -5); 228 counter.add("d", -3); 229 assertEquals("getCount(b)", counter.getCount("b"), 151); 230 assertEquals("getCount(a)", counter.getCount("a"), 95); 231 assertEquals("getCount(a)", counter.getTotal(), 338); 232 assertEquals("getItemCount", counter.getItemCount(), 4); 233 234 assertEquals("getMap", "{a=95, b=151, c=95, d=-3}", counter.toString()); 235 236 assertEquals( 237 "getKeysetSortedByKey", 238 Arrays.asList("a", "b", "c", "d"), 239 new ArrayList<>(counter.getKeysetSortedByKey())); 240 241 assertEquals( 242 "getKeysetSortedByCount(true, ucaDown)", 243 Arrays.asList("d", "c", "a", "b"), 244 new ArrayList<String>(counter.getKeysetSortedByCount(true, ucaDown))); 245 246 assertEquals( 247 "getKeysetSortedByCount(true, null), value", 248 Arrays.asList("d", "a", "c", "b"), 249 new ArrayList<>(counter.getKeysetSortedByCount(true, uca))); 250 251 assertEquals( 252 "getKeysetSortedByCount(false, ucaDown), descending", 253 Arrays.asList("b", "c", "a", "d"), 254 new ArrayList<String>(counter.getKeysetSortedByCount(false, ucaDown))); 255 256 assertEquals( 257 "getKeysetSortedByCount(false, null), descending, value", 258 Arrays.asList("b", "a", "c", "d"), 259 new ArrayList<>(counter.getKeysetSortedByCount(false, uca))); 260 } 261 TestOrganizationOrder()262 public void TestOrganizationOrder() { 263 Map<String, Organization> stringToOrg = new TreeMap<>(); 264 for (Organization org : Organization.values()) { 265 stringToOrg.put(org.toString(), org); 266 } 267 List<Organization> reordered = new ArrayList<>(stringToOrg.values()); 268 List<Organization> plain = Arrays.asList(Organization.values()); 269 for (int i = 0; i < reordered.size(); ++i) { 270 assertEquals("Items not in alphabetical order", reordered.get(i), plain.get(i)); 271 } 272 } 273 TestOrganizationNames()274 public void TestOrganizationNames() { 275 UnicodeSet uppercase = new UnicodeSet("[:uppercase:]"); 276 for (Organization org : Organization.values()) { 277 if (!uppercase.contains(org.getDisplayName().codePointAt(0))) { 278 errln("Organization name isn't titlecased: " + org + ", " + org.getDisplayName()); 279 } 280 assertEquals( 281 "Organization from enum name", org, Organization.fromString(org.toString())); 282 assertEquals( 283 "Organization from display name", 284 org, 285 Organization.fromString(org.getDisplayName())); 286 } 287 } 288 289 static final boolean SHOW_DETAILS = CldrUtility.getProperty("showdetails", false); 290 private static final CharSequence DEBUG_COMMENT = 291 "set up a case of conflict within organization"; 292 293 static class PathValueInfo { 294 private static Map<Integer, String> voteInfo; 295 private CLDRFile file; 296 PathValueInfo(Factory factory, String locale)297 public PathValueInfo(Factory factory, String locale) { 298 this.file = factory.make(locale, false); 299 } 300 getRealValue(int id)301 public String getRealValue(int id) { 302 return file.getStringValue(getRealPath(id)); 303 } 304 getRealPath(int id)305 public String getRealPath(int id) { 306 return voteInfo.get(id); 307 } 308 } 309 310 /** Test user data. Restructured to be easier to read, more typesafe */ 311 public enum TestUser { 312 unaffiliatedS(801, Organization.unaffiliated, Level.guest), 313 gnomeS(701, Organization.gnome, Level.guest), 314 gnomeV(702, Organization.gnome, Level.vetter), 315 googleV(404, Organization.google, Level.vetter), 316 googleS(411, Organization.google, Level.guest), 317 googleV2(424, Organization.google, Level.vetter), 318 appleV(304, Organization.apple, Level.vetter), 319 adobeE(204, Organization.adobe, Level.manager), 320 adobeV(209, Organization.adobe, Level.vetter), 321 ibmS(101, Organization.ibm, Level.guest), 322 microsoftV(134, Organization.microsoft, Level.vetter), 323 ibmE(114, Organization.ibm, Level.manager), 324 ibmT(129, Organization.ibm, Level.tc), 325 unaffiliatedS2(802, Organization.unaffiliated, Level.guest); 326 327 public static final Map<Integer, VoterInfo> TEST_USERS; 328 public final Integer voterId; 329 public final VoterInfo voterInfo; 330 TestUser(int intVoterId, Organization organization, Level level)331 TestUser(int intVoterId, Organization organization, Level level) { 332 voterId = intVoterId; 333 voterInfo = new VoterInfo(organization, level, name()); 334 } 335 336 static { 337 ImmutableMap.Builder<Integer, VoterInfo> temp = ImmutableMap.builder(); 338 for (TestUser testUser : values()) { temp.put(testUser.voterId, testUser.voterInfo)339 temp.put(testUser.voterId, testUser.voterInfo); 340 } 341 TEST_USERS = temp.build(); 342 } 343 } 344 345 public static final Map<Integer, VoterInfo> testdata = TestUser.TEST_USERS; 346 toVoterId(String s)347 private int toVoterId(String s) { 348 return TestUser.valueOf(s).voterId; 349 } 350 351 /** Public to use from other tests */ getTestVoterInfoList()352 public static VoterInfoList getTestVoterInfoList() { 353 return new VoterInfoList().setVoterToInfo(testdata); 354 } 355 TestTrunkStatus()356 public void TestTrunkStatus() { 357 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 358 resolver.setLocale(CLDRLocale.getInstance("de"), null); 359 resolver.setBaileyValue("bailey"); 360 resolver.setBaseline("new-item", Status.approved); 361 assertEquals("", "new-item", resolver.getWinningValue()); 362 363 /* 364 * Formerly last-release would win over trunk in a 2nd scenario here, due to 365 * the difference in status. Now last-release plays no role, that test is obsolete. 366 * Reference: https://unicode.org/cldr/trac/ticket/11916 367 */ 368 } 369 TestVoteResolverNgombaTrunkStatus()370 public void TestVoteResolverNgombaTrunkStatus() { 371 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 372 resolver.setBaileyValue("bailey"); 373 resolver.setLocale(CLDRLocale.getInstance("jgo"), null); 374 final String jgo22trunk = 375 "\uA78C"; // "[a á â ǎ b c d ɛ {ɛ́} {ɛ̂} {ɛ̌} {ɛ̀} {ɛ̄} f ɡ h i í î ǐ j k l m ḿ {m̀} 376 // {m̄} n ń ǹ {n̄} ŋ {ŋ́} {ŋ̀} {ŋ̄} ɔ {ɔ́} {ɔ̂} {ɔ̌} p {pf} s {sh} t {ts} 377 // u ú û ǔ ʉ {ʉ́} {ʉ̂} {ʉ̌} {ʉ̈} v w ẅ y z ꞌ]"; 378 resolver.setBaseline(jgo22trunk, Status.approved); // seed/jgo.xml from 22 379 // trunk 380 logln("SVN: " + jgo22trunk); 381 logln(resolver.toString()); 382 assertEquals("Winning Value", jgo22trunk, resolver.getWinningValue()); 383 } 384 TestVoteStatus()385 public void TestVoteStatus() { 386 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 387 388 resolver.setLocale(CLDRLocale.getInstance("de"), null); 389 resolver.setBaileyValue("bailey"); 390 resolver.setBaseline("foo", Status.approved); 391 resolver.add("fii", toVoterId("adobeE")); 392 resolver.add("fii", toVoterId("appleV")); 393 VoteStatus voteStatus; 394 voteStatus = resolver.getStatusForOrganization(Organization.google); 395 assertEquals("", VoteResolver.VoteStatus.ok, voteStatus); 396 voteStatus = resolver.getStatusForOrganization(Organization.apple); 397 assertEquals("", VoteResolver.VoteStatus.ok, voteStatus); 398 399 // make non-equal foo 400 String s1 = "foo"; 401 String s2 = new StringBuilder("fo").append("o").toString(); 402 if (s1 == s2) { 403 errln("Test problem"); 404 } 405 resolver.clear(); 406 resolver.setBaileyValue("bailey"); 407 resolver.setBaseline(s1, Status.approved); 408 resolver.add(s2, toVoterId("appleV")); 409 voteStatus = resolver.getStatusForOrganization(Organization.apple); 410 assertEquals("", VoteResolver.VoteStatus.ok, voteStatus); 411 } 412 TestLosingStatus()413 public void TestLosingStatus() { 414 // af 415 // losing? {baseline: {BQ, missing}, trunk: {null, null}, 416 // {orgToVotes: , totals: {}, conflicted: []}, 417 // sameVotes: [BQ], O: null, N: null, totals: {}, winning: {BQ, 418 // missing}} 419 // XPath: //ldml/localeDisplayNames/territories/territory[@type="BQ"] 420 // gcvs.openoffice_org.example.com 421 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 422 423 resolver.setLocale(CLDRLocale.getInstance("af"), null); 424 resolver.setBaseline("BQ", Status.missing); 425 resolver.setBaileyValue("bailey"); 426 VoteStatus status = resolver.getStatusForOrganization(Organization.openoffice_org); 427 assertEquals("", VoteResolver.VoteStatus.provisionalOrWorse, status); 428 429 // {lastRelease: {{0}: {1}, missing}, trunk: {null, null}, {orgToVotes: 430 // pakistan={{0}: {1}=8}, totals: {{0}: 431 // {1}=8}, conflicted: []}, sameVotes: [{0}: {1}], O: {0}: {1}, N: null, 432 // totals: {{0}: {1}=8}, winning: {{0}: 433 // {1}, approved}} 434 resolver.clear(); 435 resolver.setBaileyValue("bailey"); 436 // resolver.setLastRelease("{0}: {1}", Status.missing); 437 resolver.add("{0}: {1}", toVoterId("adobeE")); 438 status = resolver.getStatusForOrganization(Organization.openoffice_org); 439 assertEquals("", VoteResolver.VoteStatus.ok, status); 440 441 // {lastRelease: {Arabisch, approved}, trunk: {Arabisch, approved}, 442 // {orgToVotes: , totals: {}, conflicted: []}, 443 // sameVotes: [Arabisch], O: null, N: null, totals: {}, winning: 444 // {Arabisch, approved}} 445 resolver.clear(); 446 resolver.setBaileyValue("bailey"); 447 // resolver.setLastRelease("Arabisch", Status.approved); 448 resolver.setBaseline("Arabisch", Status.approved); 449 status = resolver.getStatusForOrganization(Organization.openoffice_org); 450 assertEquals("", VoteResolver.VoteStatus.ok_novotes, status); 451 } 452 TestTotalVotesStatus()453 public void TestTotalVotesStatus() { 454 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 455 456 Status oldStatus = Status.unconfirmed; 457 458 resolver.setBaileyValue("bailey"); 459 resolver.setLocale(CLDRLocale.getInstance("de"), null); 460 resolver.setBaseline("foo", oldStatus); 461 resolver.add("zebra", toVoterId("googleV")); 462 resolver.add("apple", toVoterId("appleV")); 463 464 // check that alphabetical wins when votes are equal 465 String winner = resolver.getWinningValue(); 466 Status winningStatus = resolver.getWinningStatus(); 467 assertEquals("", "apple", winner); 468 assertEquals("", Status.provisional, winningStatus); 469 470 resolver.clear(); 471 resolver.setBaileyValue("bailey"); 472 resolver.setLocale(CLDRLocale.getInstance("de"), null); 473 resolver.setBaseline("foo", oldStatus); 474 resolver.add("zebra", toVoterId("googleV")); 475 resolver.add("zebra", toVoterId("googleS")); 476 resolver.add("apple", toVoterId("appleV")); 477 478 // check that total votes over alphabetical 479 winner = resolver.getWinningValue(); 480 winningStatus = resolver.getWinningStatus(); 481 assertEquals("", "zebra", winner); 482 assertEquals("", Status.provisional, winningStatus); 483 } 484 TestVoteDowngrade()485 public void TestVoteDowngrade() { 486 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 487 488 Status oldStatus = Status.unconfirmed; 489 490 resolver.setBaileyValue("bailey"); 491 resolver.setLocale(CLDRLocale.getInstance("mt"), null); 492 resolver.setBaseline("foo", oldStatus); 493 resolver.add("aardvark", toVoterId("adobeE")); 494 resolver.add("zebra", toVoterId("ibmT")); 495 assertEquals("", "zebra", resolver.getWinningValue()); // TC vote of 20 496 // beats 497 // expert's 8 498 assertEquals("", Status.approved, resolver.getWinningStatus()); 499 500 resolver.clear(); 501 resolver.setBaileyValue("bailey"); 502 resolver.setLocale(CLDRLocale.getInstance("mt"), null); 503 resolver.setBaseline("foo", oldStatus); 504 resolver.add("aardvark", toVoterId("adobeE")); 505 resolver.add("zebra", toVoterId("ibmT")); 506 resolver.add("aardvark", toVoterId("ibmE")); 507 assertEquals("", "zebra", resolver.getWinningValue()); // TC vote of 20 508 // beats 509 // manager's 4 510 // and its own 511 // manager's 4 512 assertEquals("", Status.approved, resolver.getWinningStatus()); 513 514 resolver.clear(); 515 resolver.setBaileyValue("bailey"); 516 resolver.setLocale(CLDRLocale.getInstance("mt"), null); 517 resolver.setBaseline("foo", oldStatus); 518 resolver.add("aardvark", toVoterId("adobeE")); 519 resolver.add("zebra", toVoterId("ibmT"), Level.vetter.getVotes(Organization.ibm)); // NOTE: 520 // reduced 521 // votes: 522 // as 523 // vetter. 524 resolver.add("aardvark", toVoterId("ibmE")); 525 assertEquals("", "aardvark", resolver.getWinningValue()); // Now 526 // aardvark 527 // wins - 528 // managers 529 // win out as provisional 530 assertEquals("", Status.provisional, resolver.getWinningStatus()); 531 532 resolver.clear(); 533 resolver.setBaileyValue("bailey"); 534 resolver.setLocale(CLDRLocale.getInstance("mt"), null); 535 resolver.setBaseline("foo", oldStatus); 536 resolver.add("aardvark", toVoterId("adobeE")); 537 resolver.add("zebra", toVoterId("ibmT"), Level.vetter.getVotes(Organization.ibm)); // NOTE: 538 // reduced 539 // votes: 540 // as 541 // vetter. 542 assertEquals("", "aardvark", resolver.getWinningValue()); // Now 543 // aardvark 544 // wins - 545 // managers 546 // win out. 547 assertEquals("", Status.provisional, resolver.getWinningStatus()); 548 } 549 TestResolvedVoteCounts()550 public void TestResolvedVoteCounts() { 551 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 552 553 Status oldStatus = Status.unconfirmed; 554 555 resolver.setBaileyValue("bailey"); 556 resolver.setLocale(CLDRLocale.getInstance("de"), null); 557 resolver.setBaseline("foo", oldStatus); 558 resolver.add("zebra", toVoterId("googleV")); 559 resolver.add("apple", toVoterId("appleV")); 560 561 // check that alphabetical wins when votes are equal 562 Map<String, Long> counts = resolver.getResolvedVoteCountsIncludingIntraOrgDisputes(); 563 logln(counts.toString()); 564 assertEquals("", "foo", new ArrayList<>(counts.keySet()).get(2)); 565 566 resolver.clear(); 567 resolver.setBaileyValue("bailey"); 568 resolver.setLocale(CLDRLocale.getInstance("de"), null); 569 resolver.setBaseline("foo", Status.approved); 570 resolver.add("zebra", toVoterId("googleV")); 571 resolver.add("apple", toVoterId("appleV")); 572 counts = resolver.getResolvedVoteCountsIncludingIntraOrgDisputes(); 573 logln(counts.toString()); 574 assertEquals("", "foo", new ArrayList<>(counts.keySet()).get(0)); 575 576 resolver.clear(); 577 resolver.setBaileyValue("bailey"); 578 resolver.setLocale(CLDRLocale.getInstance("de"), null); 579 resolver.setBaseline("foo", Status.approved); 580 resolver.add("zebra", toVoterId("googleS")); 581 counts = resolver.getResolvedVoteCountsIncludingIntraOrgDisputes(); 582 logln(counts.toString()); 583 assertEquals("", "foo", new ArrayList<>(counts.keySet()).get(0)); 584 } 585 verifyRequiredVotes( VoteResolver<String> resolver, String locale, String xpath, Status baselineStatus, int required)586 private void verifyRequiredVotes( 587 VoteResolver<String> resolver, 588 String locale, 589 String xpath, 590 Status baselineStatus, 591 int required) { 592 StringBuilder sb = new StringBuilder(); 593 sb.append("Locale: " + locale); 594 resolver.clear(); 595 resolver.setBaileyValue("bailey"); 596 resolver.setBaseline("foo", baselineStatus); 597 PathHeader ph = null; 598 if (xpath != null) { 599 sb.append(" XPath: " + xpath); 600 ph = PathHeader.getFactory(testInfo.getEnglish()).fromPath(xpath); 601 } 602 resolver.setLocale(CLDRLocale.getInstance(locale), ph); 603 if (!assertEquals( 604 locale + " verifyRequiredVotes: " + ph.toString(), 605 required, 606 resolver.getRequiredVotes())) { 607 int debug = 0; 608 } 609 } 610 TestRequiredVotes()611 public void TestRequiredVotes() { 612 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 613 verifyRequiredVotes( 614 resolver, 615 "mt", 616 "//ldml/localeDisplayNames/languages/language[@type=\"fr_CA\"]", 617 Status.missing, 618 ONE_VETTER_BAR); 619 verifyRequiredVotes( 620 resolver, 621 "fr", 622 "//ldml/localeDisplayNames/languages/language[@type=\"fr_CA\"]", 623 Status.provisional, 624 TWO_VETTER_BAR); 625 verifyRequiredVotes( 626 resolver, 627 "es", 628 "//ldml/numbers/symbols[@numberSystem=\"latn\"]/group", 629 Status.approved, 630 VoteResolver.HIGH_BAR); 631 verifyRequiredVotes( 632 resolver, 633 "es", 634 "//ldml/numbers/symbols[@numberSystem=\"latn\"]/decimal", 635 Status.approved, 636 VoteResolver.HIGH_BAR); 637 verifyRequiredVotes( 638 resolver, 639 "hi", 640 "//ldml/numbers/symbols[@numberSystem=\"deva\"]/decimal", 641 Status.approved, 642 VoteResolver.HIGH_BAR); 643 verifyRequiredVotes( 644 resolver, 645 "hi", 646 "//ldml/numbers/symbols[@numberSystem=\"deva\"]/group", 647 Status.approved, 648 VoteResolver.HIGH_BAR); 649 verifyRequiredVotes( 650 resolver, 651 "ast", 652 "//ldml/numbers/symbols[@numberSystem=\"latn\"]/decimal", 653 Status.approved, 654 ONE_VETTER_BAR); 655 verifyRequiredVotes( 656 resolver, 657 "mt", 658 "//ldml/characters/exemplarCharacters", 659 Status.approved, 660 VoteResolver.HIGH_BAR); 661 verifyRequiredVotes( 662 resolver, 663 "mt", 664 "//ldml/characters/exemplarCharacters", 665 Status.approved, 666 VoteResolver.HIGH_BAR); 667 verifyRequiredVotes( 668 resolver, 669 "mt", 670 "//ldml/characters/exemplarCharacters[@type=\"auxiliary\"]", 671 Status.approved, 672 VoteResolver.HIGH_BAR); 673 verifyRequiredVotes( 674 resolver, 675 "mt", 676 "//ldml/characters/exemplarCharacters[@type=\"numbers\"]", 677 Status.approved, 678 VoteResolver.HIGH_BAR); 679 verifyRequiredVotes( 680 resolver, 681 "mt", 682 "//ldml/characters/exemplarCharacters[@type=\"punctuation\"]", 683 Status.approved, 684 VoteResolver.HIGH_BAR); 685 verifyRequiredVotes( 686 resolver, 687 "mt", 688 "//ldml/characters/exemplarCharacters[@type=\"index\"]", 689 Status.approved, 690 VoteResolver.HIGH_BAR); 691 verifyRequiredVotes( 692 resolver, 693 "es", 694 "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/days/dayContext[@type=\"format\"]/dayWidth[@type=\"wide\"]/day[@type=\"sun\"]", 695 Status.approved, 696 VoteResolver.HIGH_BAR); 697 verifyRequiredVotes( 698 resolver, 699 "ast", 700 "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/days/dayContext[@type=\"format\"]/dayWidth[@type=\"wide\"]/day[@type=\"sun\"]", 701 Status.approved, 702 ONE_VETTER_BAR); 703 verifyRequiredVotes( 704 resolver, 705 "es", 706 "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/months/monthContext[@type=\"format\"]/monthWidth[@type=\"wide\"]/month[@type=\"1\"]", 707 Status.provisional, 708 VoteResolver.LOWER_BAR); 709 verifyRequiredVotes( 710 resolver, 711 "ast", 712 "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/months/monthContext[@type=\"format\"]/monthWidth[@type=\"wide\"]/month[@type=\"1\"]", 713 Status.approved, 714 ONE_VETTER_BAR); 715 } 716 717 /** 718 * In sublocales, for a typical path, the required votes should be 4, except for a few specified 719 * locales. 720 */ TestSublocaleRequiredVotes()721 public void TestSublocaleRequiredVotes() { 722 final Set<String> eightVoteSublocales = 723 new HashSet<>( 724 Arrays.asList( 725 "pt_PT", 726 "zh_Hant", 727 "zh_Hant_HK", 728 "en_AU", 729 "en_GB", 730 "es_MX", 731 "fr_CA", 732 "es_419")); 733 final VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 734 final String path = "//ldml/annotations/annotation[@cp=\"\"][@type=\"tts\"]"; 735 for (String locale : SubmissionLocales.CLDR_OR_HIGH_LEVEL_LOCALES) { 736 if (locale.contains("_")) { 737 int expectedRequiredVotes = 738 eightVoteSublocales.contains(locale) ? TWO_VETTER_BAR : ONE_VETTER_BAR; 739 verifyRequiredVotes(resolver, locale, path, Status.approved, expectedRequiredVotes); 740 } 741 } 742 } 743 TestVoteResolver()744 public void TestVoteResolver() { 745 // to make it easier to debug failures, the first digit is an org, 746 // second is the individual in that org, and 747 // third is the voting weight. 748 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 749 String[] tests = { 750 "bailey=BAILEY", 751 "comment=regression case from John Emmons", 752 "locale=wae", 753 "oldValue=2802", 754 "oldStatus=approved", 755 "304=208027", // Apple vetter 756 // expected values 757 "value=208027", 758 "status=approved", 759 "sameVotes=208027", 760 "conflicts=[]", 761 "check", 762 // first test 763 "oldValue=old-value", 764 "oldStatus=provisional", 765 "comment=Check that identical values get the top overall vote, and that org is maxed (eg vetter + guest = vetter)", 766 "404=next", 767 "411=next", 768 "304=best", 769 // expected values 770 "value=next", 771 "sameVotes=next,best", 772 "conflicts=[]", 773 "status=provisional", 774 "check", 775 "comment=now give next a slight edge (5 to 4) with a different organization", 776 "404=next", 777 "304=best", 778 "801=next", 779 // expected values 780 "value=next", 781 "sameVotes=next", 782 "status=approved", 783 "check", 784 "comment=set up a case of conflict within organization", 785 "404=next", 786 "424=best", 787 // expected values 788 "value=best", // alphabetical 789 "sameVotes=best", 790 "conflicts=[google]", 791 "status=approved", 792 "check", 793 "comment=now cross-organizational conflict, also check for max value in same organization (4, 1) => 4 not 5", 794 "404=next", 795 "424=best", 796 "411=best", 797 "304=best", 798 // expected values 799 "conflicts=[google]", 800 "value=best", 801 "sameVotes=best", 802 "status=approved", 803 "check", 804 "comment=now clear winner 8 over 4", 805 "404=next", 806 // "424=best", 807 "411=best", 808 "304=best", 809 "204=primo", 810 "114=primo", 811 // expected values 812 "conflicts=[]", 813 "value=primo", 814 "sameVotes=primo", 815 "status=approved", 816 "check", 817 "comment=now not so clear, throw in a guest value. So it is 8 to 5. (used to be provisional)", 818 "404=next", 819 // "424=best", 820 "411=best", 821 "304=best", 822 "204=primo", 823 "114=primo", 824 "101=best", 825 // expected values 826 "conflicts=[]", 827 "value=primo", 828 "status=approved", 829 "check", 830 "comment=set up vote of 4 in established locale, with old provisional value", 831 "locale=fr", 832 "404=best", 833 "oldStatus=provisional", 834 // expected values 835 "value=best", 836 "sameVotes=best", 837 "status=contributed", 838 "conflicts=[]", 839 "check", 840 "comment=now set up vote of 4 in established locale, but with old contributed value", 841 "oldStatus=contributed", 842 // expected values 843 "value=old-value", 844 "sameVotes=old-value", 845 "status=contributed", 846 "conflicts=[]", 847 "check", 848 "comment=now set up vote of 1 + 1 in established locale, and with old contributed value", 849 "411=best", 850 "101=best", 851 "oldStatus=contributed", 852 // expected values 853 "value=best", 854 "sameVotes=best", 855 "status=contributed", 856 "conflicts=[]", 857 "check", 858 }; 859 String expectedValue = null; 860 String expectedConflicts = null; 861 Status expectedStatus = null; 862 String oldValue = null; 863 Status oldStatus = null; 864 String baileyValue = null; 865 List<String> sameVotes = null; 866 String locale = null; 867 Map<Integer, String> values = new TreeMap<>(); 868 int counter = -1; 869 870 for (String test : tests) { 871 String[] item = test.split("="); 872 String name = item[0]; 873 String value = item.length < 2 ? null : item[1]; 874 if (name.equalsIgnoreCase("comment")) { 875 logln("#\t" + value); 876 // System.out.println("#\t" + value); 877 if (DEBUG_COMMENT != null && value.contains(DEBUG_COMMENT)) { 878 int x = 0; 879 } 880 } else if (name.equalsIgnoreCase("locale")) { 881 locale = value; 882 } else if (name.equalsIgnoreCase("bailey")) { 883 baileyValue = value; 884 } else if (name.equalsIgnoreCase("oldValue")) { 885 oldValue = value; 886 } else if (name.equalsIgnoreCase("oldStatus")) { 887 oldStatus = Status.valueOf(value); 888 } else if (name.equalsIgnoreCase("value")) { 889 expectedValue = value; 890 } else if (name.equalsIgnoreCase("sameVotes")) { 891 sameVotes = 892 value == null ? new ArrayList<>(0) : Arrays.asList(value.split(",\\s*")); 893 } else if (name.equalsIgnoreCase("status")) { 894 expectedStatus = Status.valueOf(value); 895 } else if (name.equalsIgnoreCase("conflicts")) { 896 expectedConflicts = value; 897 } else if (DIGITS.containsAll(name)) { 898 final int voter = Integer.parseInt(name); 899 if (value == null || value.equals("null")) { 900 values.remove(voter); 901 } else { 902 values.put(voter, value); 903 } 904 } else if (name.equalsIgnoreCase("check")) { 905 counter++; 906 // load the resolver 907 resolver.setBaileyValue(baileyValue); 908 resolver.setLocale(CLDRLocale.getInstance(locale), null); 909 resolver.setBaseline(oldValue, oldStatus); 910 for (int voter : values.keySet()) { 911 resolver.add(values.get(voter), voter); 912 } 913 // print the contents 914 logln(counter + "\t" + values); 915 logln(resolver.toString()); 916 // now print the values 917 assertEquals(counter + " value", expectedValue, resolver.getWinningValue()); 918 assertEquals( 919 counter + " sameVotes", 920 sameVotes.toString(), 921 resolver.getValuesWithSameVotes().toString()); 922 assertEquals(counter + " status", expectedStatus, resolver.getWinningStatus()); 923 assertEquals( 924 counter + " conflicts", 925 expectedConflicts, 926 resolver.getConflictedOrganizations().toString()); 927 resolver.clear(); 928 resolver.setBaileyValue("bailey"); 929 values.clear(); 930 } else { 931 errln("unknown command:\t" + test); 932 } 933 } 934 } 935 936 void assertSpecialLocale(String loc, SpecialLocales.Type type) { 937 assertEquals( 938 "SpecialLocales type for " + loc, 939 type, 940 SpecialLocales.getType(CLDRLocale.getInstance(loc))); 941 } 942 943 public void TestSpecialLocales() { 944 assertSpecialLocale("sr", null); 945 assertSpecialLocale("ha_NE", SpecialLocales.Type.algorithmic); 946 assertSpecialLocale("sr_Latn", SpecialLocales.Type.algorithmic); 947 assertSpecialLocale("sr_Latn_BA", SpecialLocales.Type.algorithmic); 948 assertSpecialLocale("yue_Hans", null); // not readonly, because it is not policy DISCARD 949 assertSpecialLocale("en", SpecialLocales.Type.readonly); 950 assertSpecialLocale("en_ZZ_PROGRAMMERESE", null); // not defined 951 assertSpecialLocale(LocaleNames.UND, null); 952 assertSpecialLocale(LocaleNames.MUL, SpecialLocales.Type.scratch); 953 assertSpecialLocale("mul_ZZ", SpecialLocales.Type.scratch); 954 assertSpecialLocale("und_001", null); // not defined 955 956 CLDRLocale sr_Latn = CLDRLocale.getInstance("sr_Latn"); 957 CLDRLocale sr_Latn_BA = CLDRLocale.getInstance("sr_Latn_BA"); 958 logln("sr_Latn raw comment = " + SpecialLocales.getCommentRaw(sr_Latn)); 959 assertTrue( 960 "sr_Latn raw contains @ sign", SpecialLocales.getCommentRaw(sr_Latn).contains("@")); 961 962 logln("sr_Latn comment = " + SpecialLocales.getComment(sr_Latn)); 963 assertTrue( 964 "sr_Latn comment does NOT contain @ sign", 965 !SpecialLocales.getComment(sr_Latn).contains("@")); 966 logln("sr_Latn_BA raw comment = " + SpecialLocales.getCommentRaw(sr_Latn_BA)); 967 assertTrue( 968 "sr_Latn_BA raw contains '@sr_Latn_BA'", 969 SpecialLocales.getCommentRaw(sr_Latn_BA).contains("@sr_Latn_BA")); 970 } 971 972 public void TestCLDRURLS() { 973 final String KOREAN_LANGUAGE = "//ldml/localeDisplayNames/languages/language[@type=\"ko\"]"; 974 final String KOREAN_LANGUAGE_STRID = "821c2a2fc5c206d"; 975 final CLDRLocale maltese = CLDRLocale.getInstance("mt"); 976 assertEquals( 977 "base", "https://st.unicode.org/cldr-apps", CLDRConfig.getInstance().urls().base()); 978 assertEquals( 979 "locales list", 980 "https://st.unicode.org/cldr-apps/v#locales///", 981 CLDRConfig.getInstance().urls().forSpecial(CLDRURLS.Special.Locales)); 982 assertEquals( 983 "maltese", 984 "https://st.unicode.org/cldr-apps/v#/mt//", 985 CLDRConfig.getInstance().urls().forLocale(maltese)); 986 assertEquals( 987 "korean in maltese", 988 "https://st.unicode.org/cldr-apps/v#/mt//" + KOREAN_LANGUAGE_STRID, 989 CLDRConfig.getInstance().urls().forXpath(maltese, KOREAN_LANGUAGE)); 990 assertEquals( 991 "korean in maltese via stringid", 992 "https://st.unicode.org/cldr-apps/v#/mt//" + KOREAN_LANGUAGE_STRID, 993 CLDRConfig.getInstance().urls().forXpathHexId(maltese, KOREAN_LANGUAGE_STRID)); 994 assertEquals( 995 "south east asia in maltese", 996 "https://st.unicode.org/cldr-apps/v#/mt/C_SEAsia/", 997 CLDRConfig.getInstance().urls().forPage(maltese, PageId.C_SEAsia)); 998 try { 999 String ret = CLDRConfig.getInstance().urls().forXpathHexId(maltese, KOREAN_LANGUAGE); 1000 errln("Error- expected forXpathHexId to choke on an xpath but got " + ret); 1001 } catch (IllegalArgumentException iae) { 1002 logln("GOOD: forXpathHexId Caught expected " + iae); 1003 } 1004 try { 1005 String ret = CLDRConfig.getInstance().urls().forXpath(maltese, KOREAN_LANGUAGE_STRID); 1006 errln("Error- expected forXpath to choke on a hexid but got " + ret); 1007 } catch (IllegalArgumentException iae) { 1008 logln("GOOD: forXpath Caught expected " + iae); 1009 } 1010 1011 assertEquals( 1012 "korean in maltese - absoluteUrl", 1013 "https://st.unicode.org/cldr-apps/v#/mt//" + KOREAN_LANGUAGE_STRID, 1014 CLDRConfig.getInstance().absoluteUrls().forXpath(maltese, KOREAN_LANGUAGE)); 1015 } 1016 1017 static final UnicodeMap<String> SCRIPTS = 1018 ICUPropertyFactory.make().getProperty("script").getUnicodeMap_internal(); 1019 static final UnicodeMap<String> GC = 1020 ICUPropertyFactory.make().getProperty("general_category").getUnicodeMap_internal(); 1021 1022 public void TestUnicodeMapCompose() { 1023 logln("Getting Scripts"); 1024 1025 UnicodeMap.Composer<String> composer = 1026 new UnicodeMap.Composer<>() { 1027 @Override 1028 public String compose(int codepoint, String string, String a, String b) { 1029 return a.toString() + "_" + b.toString(); 1030 } 1031 }; 1032 1033 logln("Trying Compose"); 1034 1035 UnicodeMap<String> composed = 1036 ((UnicodeMap) SCRIPTS.cloneAsThawed()).composeWith(GC, composer); 1037 String last = ""; 1038 for (int i = 0; i < 0x10FFFF; ++i) { 1039 String comp = composed.getValue(i); 1040 String gc = GC.getValue(i); 1041 String sc = SCRIPTS.getValue(i); 1042 if (!comp.equals(composer.compose(i, null, sc, gc))) { 1043 errln("Failed compose at: " + i); 1044 break; 1045 } 1046 if (!last.equals(comp)) { 1047 logln(Utility.hex(i) + "\t" + comp); 1048 last = comp; 1049 } 1050 } 1051 } 1052 1053 private static final int SET_LIMIT = 0x10FFFF; 1054 private static final int CHECK_LIMIT = 0xFFFF; 1055 private static final NumberFormat pf = NumberFormat.getPercentInstance(); 1056 private static final NumberFormat nf = NumberFormat.getInstance(); 1057 1058 public void TestUnicodeMapTime() { 1059 boolean shortTest = getInclusion() < 10; 1060 double hashTime, umTime, icuTime, treeTime; 1061 int warmup = shortTest ? 1 : 20; 1062 umTime = checkUnicodeMapSetTime(warmup, 0); 1063 hashTime = checkUnicodeMapSetTime(warmup, 1); 1064 logln("Percentage: " + pf.format(hashTime / umTime)); 1065 treeTime = checkUnicodeMapSetTime(warmup, 3); 1066 logln("Percentage: " + pf.format(treeTime / umTime)); 1067 1068 if (shortTest) { 1069 return; 1070 } 1071 1072 umTime = checkUnicodeMapGetTime(1000, 0); 1073 hashTime = checkUnicodeMapGetTime(1000, 1); 1074 logln("Percentage: " + pf.format(hashTime / umTime)); 1075 icuTime = checkUnicodeMapGetTime(1000, 2); 1076 logln("Percentage: " + pf.format(icuTime / umTime)); 1077 treeTime = checkUnicodeMapGetTime(1000, 3); 1078 logln("Percentage: " + pf.format(treeTime / umTime)); 1079 } 1080 1081 private static final int propEnum = UProperty.GENERAL_CATEGORY; 1082 1083 private double checkUnicodeMapSetTime(int iterations, int type) { 1084 _checkUnicodeMapSetTime(1, type); 1085 double result = _checkUnicodeMapSetTime(iterations, type); 1086 logln( 1087 (type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") 1088 + "\t" 1089 + nf.format(result)); 1090 return result; 1091 } 1092 1093 private double _checkUnicodeMapSetTime(int iterations, int type) { 1094 UnicodeMap<String> map1 = SCRIPTS; 1095 Map<Integer, String> map2 = map1.putAllCodepointsInto(new HashMap<Integer, String>()); 1096 Map<Integer, String> map3 = new TreeMap<>(map2); 1097 System.gc(); 1098 double start = System.currentTimeMillis(); 1099 for (int j = 0; j < iterations; ++j) 1100 for (int cp = 0; cp <= SET_LIMIT; ++cp) { 1101 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); 1102 if (enumValue <= 0) continue; // for smaller set 1103 String value = 1104 UCharacter.getPropertyValueName( 1105 propEnum, enumValue, UProperty.NameChoice.LONG); 1106 switch (type) { 1107 case 0: 1108 map1.put(cp, value); 1109 break; 1110 case 1: 1111 map2.put(cp, value); 1112 break; 1113 case 3: 1114 map3.put(cp, value); 1115 break; 1116 } 1117 } 1118 double end = System.currentTimeMillis(); 1119 return (end - start) / 1000 / iterations; 1120 } 1121 1122 private double checkUnicodeMapGetTime(int iterations, int type) { 1123 UnicodeMap<String> map1 = new UnicodeMap<>(); 1124 Map<Integer, String> map2 = map1.putAllCodepointsInto(new HashMap<Integer, String>()); 1125 Map<Integer, String> map3 = new TreeMap<>(); 1126 _checkUnicodeMapGetTime(map1, map2, map3, 1, type); // warmup 1127 double result = _checkUnicodeMapGetTime(map1, map2, map3, iterations, type); 1128 logln( 1129 (type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") 1130 + "\t" 1131 + nf.format(result)); 1132 return result; 1133 } 1134 1135 private double _checkUnicodeMapGetTime( 1136 UnicodeMap<String> map1, 1137 Map<Integer, String> map2, 1138 Map<Integer, String> map3, 1139 int iterations, 1140 int type) { 1141 System.gc(); 1142 double start = System.currentTimeMillis(); 1143 for (int j = 0; j < iterations; ++j) 1144 for (int cp = 0; cp < CHECK_LIMIT; ++cp) { 1145 switch (type) { 1146 case 0: 1147 map1.getValue(cp); 1148 break; 1149 case 1: 1150 map2.get(cp); 1151 break; 1152 case 2: 1153 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); 1154 UCharacter.getPropertyValueName( 1155 propEnum, enumValue, UProperty.NameChoice.LONG); 1156 break; 1157 case 3: 1158 map3.get(cp); 1159 break; 1160 } 1161 } 1162 double end = System.currentTimeMillis(); 1163 return (end - start) / 1000 / iterations; 1164 } 1165 1166 public void TestStevenTest() { 1167 VoteResolver<String> resolver = new VoteResolver<>(getTestVoterInfoList()); 1168 1169 String tests[] = { 1170 "bailey=BAILEY", 1171 "comment=Steven Loomis test case tweaked by Parthinator", 1172 "locale=wae", 1173 "oldValue=_", 1174 "oldStatus=approved", 1175 "304=test", // Apple vetter 1176 // expected values 1177 "value=test", 1178 "status=approved", 1179 "sameVotes=test", 1180 "conflicts=[]", 1181 "check", 1182 1183 // test1 1184 "comment=timestamp case1", 1185 "locale=de", 1186 "oldValue=old-value", 1187 "oldStatus=provisional", 1188 "404=Foo", 1189 "424=Bar", 1190 // expected 1191 "value=Bar", 1192 "status=provisional", 1193 "sameVotes=Bar, test", 1194 "conflicts=[google]", 1195 "check", 1196 1197 // test2 1198 "comment=timestamp case2", 1199 "locale=de", 1200 "oldValue=Bar", 1201 "oldStatus=provisional", 1202 "424=Foo", 1203 "404=Bar", 1204 // expected values 1205 "value=Bar", 1206 "status=provisional", 1207 "sameVotes=Bar, test", 1208 "conflicts=[google]", 1209 "check", 1210 1211 // test 3 1212 "comment=timestamp unaffiliated case", 1213 "locale=de", 1214 "oldValue=_", 1215 "oldStatus=unconfirmed", 1216 // # // G vetter A 1217 // timestamp=1 1218 "801=Foo", 1219 // timestamp=2 1220 "802=Bar", 1221 // expected values 1222 "value=Bar", 1223 "status=contributed", 1224 "sameVotes=Bar", 1225 "conflicts=[google, unaffiliated]", 1226 "check", 1227 }; 1228 1229 String expectedValue = null; 1230 String expectedConflicts = null; 1231 Status expectedStatus = null; 1232 String oldValue = null; 1233 Status oldStatus = null; 1234 String baileyValue = null; 1235 List<String> sameVotes = null; 1236 String locale = null; 1237 int voteEntries = 0; 1238 Map<Integer, String> values = new TreeMap<>(); 1239 Map<Integer, VoteEntries> valuesMap = new TreeMap<>(); 1240 1241 int counter = -1; 1242 1243 for (String test : tests) { 1244 String[] item = test.split("="); 1245 String name = item[0]; 1246 String value = item.length < 2 ? null : item[1]; 1247 if (name.equalsIgnoreCase("comment")) { 1248 logln("#\t" + value); 1249 // System.out.println("#\t" + value); 1250 if (DEBUG_COMMENT != null && value.contains(DEBUG_COMMENT)) { 1251 int x = 0; 1252 } 1253 } else if (name.equalsIgnoreCase("locale")) { 1254 locale = value; 1255 } else if (name.equalsIgnoreCase("oldValue")) { 1256 oldValue = value; 1257 } else if (name.equalsIgnoreCase("oldStatus")) { 1258 oldStatus = Status.valueOf(value); 1259 } else if (name.equalsIgnoreCase("value")) { 1260 expectedValue = value; 1261 } else if (name.equalsIgnoreCase("bailey")) { 1262 baileyValue = value; 1263 } else if (name.equalsIgnoreCase("sameVotes")) { 1264 sameVotes = 1265 value == null ? new ArrayList<>(0) : Arrays.asList(value.split(",\\s*")); 1266 } else if (name.equalsIgnoreCase("status")) { 1267 expectedStatus = Status.valueOf(value); 1268 } else if (name.equalsIgnoreCase("conflicts")) { 1269 expectedConflicts = value; 1270 } else if (DIGITS.containsAll(name)) { 1271 final int voter = Integer.parseInt(name); 1272 if (value == null || value.equals("null")) { 1273 values.remove(voter); 1274 for (Map.Entry<Integer, VoteEntries> entry : valuesMap.entrySet()) { 1275 if (entry.getValue().getVoter() == voter) { 1276 valuesMap.remove(entry.getKey()); 1277 } 1278 } 1279 } else { 1280 values.put(voter, value); 1281 valuesMap.put(++voteEntries, new VoteEntries(voter, value)); 1282 } 1283 } else if (name.equalsIgnoreCase("check")) { 1284 counter++; 1285 // load the resolver 1286 resolver.setBaileyValue(baileyValue); 1287 resolver.setLocale(CLDRLocale.getInstance(locale), null); 1288 resolver.setBaseline(oldValue, oldStatus); 1289 for (int voteEntry : valuesMap.keySet()) { 1290 1291 resolver.add( 1292 valuesMap.get(voteEntry).getValue(), 1293 valuesMap.get(voteEntry).getVoter()); 1294 } 1295 // print the contents 1296 logln(counter + "\t" + values); 1297 logln(resolver.toString()); 1298 // now print the values 1299 assertEquals(counter + " value", expectedValue, resolver.getWinningValue()); 1300 assertEquals( 1301 counter + " sameVotes", 1302 sameVotes.toString(), 1303 resolver.getValuesWithSameVotes().toString()); 1304 assertEquals(counter + " status", expectedStatus, resolver.getWinningStatus()); 1305 assertEquals( 1306 counter + " conflicts", 1307 expectedConflicts, 1308 resolver.getConflictedOrganizations().toString()); 1309 resolver.clear(); 1310 values.clear(); 1311 } else { 1312 errln("unknown command:\t" + test); 1313 } 1314 } 1315 } 1316 1317 public void testBaileyVotes() { 1318 VoterInfoList vil = new VoterInfoList().setVoterToInfo(TestUser.TEST_USERS); 1319 VoteResolver<String> resolver = new VoteResolver<>(vil); 1320 CLDRLocale locale = CLDRLocale.getInstance("de"); 1321 PathHeader path = null; 1322 1323 /* 1324 * Simple case, all = bailey -- should get INHERITANCE_MARKER now that we have "dropped hard inheritance" 1325 */ 1326 resolver.setLocale(locale, path); 1327 resolver.setBaileyValue("bailey"); 1328 resolver.setBaseline("foo", Status.approved); 1329 1330 resolver.add("bailey", TestUser.appleV.voterId); 1331 resolver.add("bailey", TestUser.microsoftV.voterId); 1332 resolver.add("bailey", TestUser.googleV.voterId); 1333 if (VoteResolver.DROP_HARD_INHERITANCE) { 1334 assertEquals( 1335 "Simple case, all = bailey", 1336 CldrUtility.INHERITANCE_MARKER, 1337 resolver.getWinningValue()); 1338 } else { 1339 assertEquals("Simple case, all = bailey", "bailey", resolver.getWinningValue()); 1340 } 1341 1342 /* 1343 * Another simple case, all = INHERITANCE_MARKER 1344 * Added per https://unicode.org/cldr/trac/ticket/11299 1345 */ 1346 resolver.clear(); 1347 resolver.setLocale(locale, path); 1348 resolver.setBaileyValue("bailey"); 1349 resolver.setBaseline("foo", Status.approved); 1350 1351 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.appleV.voterId); 1352 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.microsoftV.voterId); 1353 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.googleV.voterId); 1354 assertEquals( 1355 "Another simple case, all = INHERITANCE_MARKER", 1356 CldrUtility.INHERITANCE_MARKER, 1357 resolver.getWinningValue()); 1358 1359 /* 1360 * INHERITANCE_MARKER should win here, having more votes than bailey. 1361 * Changed per https://unicode.org/cldr/trac/ticket/11299 1362 */ 1363 resolver.clear(); 1364 resolver.setLocale(locale, path); 1365 resolver.setBaileyValue("bailey"); 1366 resolver.setBaseline("foo", Status.approved); 1367 1368 resolver.add("bailey", TestUser.appleV.voterId); 1369 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.microsoftV.voterId); 1370 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.googleV.voterId); 1371 assertEquals( 1372 "The bailey value and explicit value combine to win", 1373 CldrUtility.INHERITANCE_MARKER, 1374 resolver.getWinningValue()); 1375 1376 /* 1377 * INHERITANCE_MARKER should win here, having equal number of votes with bailey; 1378 * first they combine to win over other-vote. 1379 * Changed per https://unicode.org/cldr/trac/ticket/11299 1380 */ 1381 resolver.clear(); 1382 resolver.setLocale(locale, path); 1383 resolver.setBaileyValue("bailey"); 1384 resolver.setBaseline("foo", Status.approved); 1385 1386 resolver.add("bailey", TestUser.appleV.voterId); 1387 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.microsoftV.voterId); 1388 resolver.add("other-vote", TestUser.googleV.voterId); 1389 assertEquals( 1390 "The bailey value and explicit value combine to win again", 1391 CldrUtility.INHERITANCE_MARKER, 1392 resolver.getWinningValue()); 1393 1394 /* 1395 * Split vote, no action 1396 */ 1397 resolver.clear(); 1398 resolver.setLocale(locale, path); 1399 resolver.setBaileyValue("bailey"); 1400 resolver.setBaseline("foo", Status.approved); 1401 1402 resolver.add("bailey", TestUser.appleV.voterId); 1403 resolver.add("not-bailey", TestUser.microsoftV.voterId); 1404 resolver.add("other-vote", TestUser.googleV.voterId); 1405 assertEquals("Split vote, no action", "foo", resolver.getWinningValue()); 1406 1407 /* 1408 * Bailey should lose even if it has MORE votes than INHERITANCE_MARKER, now that we 1409 * have "dropped hard inheritance" 1410 */ 1411 resolver.clear(); 1412 resolver.setLocale(locale, path); 1413 resolver.setBaileyValue("bailey"); 1414 resolver.setBaseline("foo", Status.approved); 1415 1416 resolver.add("bailey", TestUser.googleV.voterId); 1417 resolver.add("bailey", TestUser.appleV.voterId); 1418 resolver.add(CldrUtility.INHERITANCE_MARKER, TestUser.microsoftV.voterId); 1419 resolver.add("other-vote", TestUser.adobeV.voterId); 1420 resolver.add("other-vote", TestUser.gnomeV.voterId); 1421 if (VoteResolver.DROP_HARD_INHERITANCE) { 1422 assertEquals( 1423 "Bailey never beats INHERITANCE_MARKER", 1424 CldrUtility.INHERITANCE_MARKER, 1425 resolver.getWinningValue()); 1426 } else { 1427 assertEquals( 1428 "Bailey can beat INHERITANCE_MARKER if not dropped", 1429 "bailey", 1430 resolver.getWinningValue()); 1431 } 1432 } 1433 1434 /** Test XMLUploader.writeBulkInfoHtml */ 1435 public void TestBulkUploadHtml() { 1436 StringWriter out = new StringWriter(); 1437 final String bulkStage = "submit"; 1438 try { 1439 XMLUploader.writeBulkInfoHtml(bulkStage, out); 1440 } catch (Exception e) { 1441 errln("Exception for writeBulkInfoHtml in TestBulkUploadHtml: " + e); 1442 } 1443 final String expected = 1444 "<div class='bulkNextInfo'>\n<ul>\n<li class='header'>Bulk Upload:</li>\n" 1445 + "<li class='inactive'>\n<h1>1. upload</h1>\n<h2>Upload XML file</h2>\n</li>\n" 1446 + "<li class='inactive'>\n<h1>2. check</h1>\n<h2>Verify valid XML</h2>\n</li>\n" 1447 + "<li class='inactive'>\n<h1>3. test</h1>\n<h2>Test for CLDR errors</h2>\n</li>\n" 1448 + "<li class='active'>\n<h1>4. submit</h1>\n<h2>Data submitted into SurveyTool</h2>\n</li>\n" 1449 + "</ul>\n</div>\n"; 1450 assertEquals("writeBulkInfoHtml", expected, out.toString()); 1451 } 1452 1453 /** 1454 * Verify that VettingViewer.getMissingStatus returns MissingStatus.PRESENT for a typical path 1455 * in a well-populated locale 1456 * 1457 * <p>Ideally we should also test for MissingStatus.DISPUTED, etc.; that's more difficult 1458 */ 1459 public void TestMissingStatus() { 1460 final String path = 1461 "//ldml/units/unitLength[@type=\"short\"]/unit[@type=\"volume-cup\"]/displayName"; 1462 final String locale = "fr"; 1463 final CLDRFile cldrFile = testInfo.getCLDRFile(locale, true); 1464 final MissingStatus expected = MissingStatus.PRESENT; 1465 // Note: VettingViewer.getMissingStatus reports PRESENT for items with ↑↑↑ and absent if the 1466 // item 1467 // is removed to inherit from root, even though the value obtained is the same in either 1468 // case; 1469 // so for path pick an item that does not have ↑↑↑, otherwise when that item is stripped for 1470 // production data the test will fail. 1471 final MissingStatus status = 1472 VettingViewer.getMissingStatus(cldrFile, path, true /* latin */); 1473 if (status != expected) { 1474 errln( 1475 "Got getMissingStatus = " 1476 + status.toString() 1477 + "; expected " 1478 + expected.toString()); 1479 } 1480 } 1481 1482 /** Check that expected paths are Aliased, and have debugging code */ 1483 public void TestMissingGrammar() { 1484 // https://cldr-smoke.unicode.org/cldr-apps/v#/hu/Length/a4915bf505ffb49 1485 final String path = 1486 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"one\"][@case=\"accusative\"]"; 1487 checkGrammarCoverage( 1488 "hr", 1489 path, 1490 MissingStatus.PRESENT, 1491 DEBUG, 1492 1, 1493 0, 1494 0, 1495 0, 1496 0); // this isn't a very good test, since we have to adjust each time. Should create 1497 // fake cldr data instead 1498 checkGrammarCoverage("kw", path, MissingStatus.ABSENT, false, 0, 0, 1, 1, 0); 1499 checkGrammarCoverage("en_NZ", path, MissingStatus.ALIASED, DEBUG, 1, 0, 0, 0, 0); 1500 } 1501 1502 /** 1503 * Check the getMissingStatus and getStatus. Note that the values may need to be adjusted in 1504 * successive versions. The sizes are expected sizes. 1505 * 1506 * @param locale 1507 * @param path 1508 * @param statusExpected 1509 * @param debug TODO 1510 */ 1511 public void checkGrammarCoverage( 1512 final String locale, 1513 final String path, 1514 MissingStatus statusExpected, 1515 boolean debug, 1516 int... sizes) { 1517 final CLDRFile cldrFile = testInfo.getCLDRFile(locale, true); 1518 final MissingStatus expected = statusExpected; 1519 final MissingStatus status = 1520 VettingViewer.getMissingStatus(cldrFile, path, true /* latin */); 1521 if (status != expected) { 1522 errln( 1523 locale 1524 + " got getMissingStatus = " 1525 + status.toString() 1526 + "; expected " 1527 + expected.toString()); 1528 } 1529 Iterable<String> pathsToTest = Collections.singleton(path); 1530 Counter<org.unicode.cldr.util.Level> foundCounter = new Counter<>(); 1531 Counter<org.unicode.cldr.util.Level> unconfirmedCounter = new Counter<>(); 1532 Counter<org.unicode.cldr.util.Level> missingCounter = new Counter<>(); 1533 Relation<MissingStatus, String> missingPaths = 1534 new Relation( 1535 new TreeMap<MissingStatus, String>(), TreeSet.class, Ordering.natural()); 1536 Set<String> unconfirmedPaths = new TreeSet<>(); 1537 VettingViewer.getStatus( 1538 pathsToTest, 1539 cldrFile, 1540 PathHeader.getFactory(), 1541 foundCounter, 1542 unconfirmedCounter, 1543 missingCounter, 1544 missingPaths, 1545 unconfirmedPaths); 1546 assertEquals(locale + " foundCounter (0)", sizes[0], foundCounter.getTotal()); 1547 assertEquals(locale + " unconfirmedCounter (1)", sizes[1], unconfirmedCounter.getTotal()); 1548 assertEquals(locale + " missingCounter (2)", sizes[2], missingCounter.getTotal()); 1549 assertEquals(locale + " missingPaths (3)", sizes[3], missingPaths.size()); 1550 assertEquals(locale + " unconfirmedPaths (4)", sizes[4], unconfirmedPaths.size()); 1551 showStatusResults( 1552 locale, 1553 foundCounter, 1554 unconfirmedCounter, 1555 missingCounter, 1556 missingPaths, 1557 unconfirmedPaths); 1558 if (debug) { 1559 foundCounter.clear(); 1560 unconfirmedCounter.clear(); 1561 missingCounter.clear(); 1562 missingPaths.clear(); 1563 unconfirmedPaths.clear(); 1564 pathsToTest = cldrFile.fullIterable(); 1565 VettingViewer.getStatus( 1566 pathsToTest, 1567 cldrFile, 1568 PathHeader.getFactory(), 1569 foundCounter, 1570 unconfirmedCounter, 1571 missingCounter, 1572 missingPaths, 1573 unconfirmedPaths); 1574 showStatusResults( 1575 locale, 1576 foundCounter, 1577 unconfirmedCounter, 1578 missingCounter, 1579 missingPaths, 1580 unconfirmedPaths); 1581 } 1582 } 1583 1584 public void showStatusResults( 1585 final String locale, 1586 Counter<org.unicode.cldr.util.Level> foundCounter, 1587 Counter<org.unicode.cldr.util.Level> unconfirmedCounter, 1588 Counter<org.unicode.cldr.util.Level> missingCounter, 1589 Relation<MissingStatus, String> missingPaths, 1590 Set<String> unconfirmedPaths) { 1591 warnln( 1592 "\n" 1593 + locale 1594 + " foundCounter:\t" 1595 + foundCounter 1596 + "\n" 1597 + locale 1598 + " unconfirmedCounter:\t" 1599 + unconfirmedCounter 1600 + "\n" 1601 + locale 1602 + " missingCounter:\t" 1603 + missingCounter 1604 + "\n" 1605 + locale 1606 + " unconfirmedPaths:\t" 1607 + unconfirmedPaths 1608 + "\n" 1609 + locale 1610 + " missing paths (modern):"); 1611 int count = 0; 1612 for (Entry<MissingStatus, String> entry : missingPaths.entrySet()) { 1613 final MissingStatus missingStatus = entry.getKey(); 1614 final String missingPath = entry.getValue(); 1615 warnln( 1616 ++count 1617 + "\t" 1618 + locale 1619 + "\t" 1620 + missingStatus 1621 + "\t" 1622 + missingPath 1623 + "\t" 1624 + SUPPLEMENTAL_DATA_INFO.getCoverageLevel(missingPath, locale)); 1625 } 1626 } 1627 1628 /** 1629 * Test the function VoteResolver.Level.canCreateOrSetLevelTo() 1630 * 1631 * <p>Compare org.unicode.cldr.unittest.web.TestUserRegistry.TestCanSetUserLevel() 1632 */ 1633 public void TestCanCreateOrSetLevelTo() { 1634 if (Level.vetter.canCreateOrSetLevelTo(Level.guest) 1635 || Level.anonymous.canCreateOrSetLevelTo(Level.guest) 1636 || Level.guest.canCreateOrSetLevelTo(Level.locked) 1637 || Level.locked.canCreateOrSetLevelTo(Level.locked)) { 1638 errln("Only managers and above can change levels at all"); 1639 } 1640 if (Level.manager.canCreateOrSetLevelTo(Level.tc) 1641 || Level.manager.canCreateOrSetLevelTo(Level.admin) 1642 || Level.tc.canCreateOrSetLevelTo(Level.admin)) { 1643 errln("Can’t change anyone to a more privileged level than you"); 1644 } 1645 } 1646 } 1647