1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 1996-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10 package android.icu.dev.test.translit; 11 12 import java.util.Comparator; 13 import java.util.HashMap; 14 import java.util.HashSet; 15 import java.util.Iterator; 16 import java.util.Map; 17 import java.util.Map.Entry; 18 import java.util.Random; 19 import java.util.Set; 20 import java.util.SortedMap; 21 import java.util.SortedSet; 22 import java.util.TreeMap; 23 import java.util.TreeSet; 24 25 import org.junit.Test; 26 27 import android.icu.dev.test.TestBoilerplate; 28 import android.icu.dev.test.TestFmwk; 29 import android.icu.dev.util.CollectionUtilities; 30 import android.icu.dev.util.UnicodeMap; 31 import android.icu.dev.util.UnicodeMap.EntryRange; 32 import android.icu.dev.util.UnicodeMapIterator; 33 import android.icu.impl.Utility; 34 import android.icu.lang.UCharacter; 35 import android.icu.lang.UProperty; 36 import android.icu.text.UTF16; 37 import android.icu.text.UnicodeSet; 38 39 /** 40 * @test 41 * @summary General test of UnicodeSet 42 */ 43 public class UnicodeMapTest extends TestFmwk { 44 45 static final int MODIFY_TEST_LIMIT = 32; 46 static final int MODIFY_TEST_ITERATIONS = 100000; 47 48 @Test 49 public void TestIterations() { 50 UnicodeMap<Double> foo = new UnicodeMap(); 51 checkToString(foo, ""); 52 foo.put(3, 6d).put(5, 10d); 53 checkToString(foo, "0003=6.0\n0005=10.0\n"); 54 foo.put(0x10FFFF, 666d); 55 checkToString(foo, "0003=6.0\n0005=10.0\n10FFFF=666.0\n"); 56 foo.put("neg", -555d); 57 checkToString(foo, "0003=6.0\n0005=10.0\n10FFFF=666.0\n006E,0065,0067=-555.0\n"); 58 59 double i = 0; 60 for (EntryRange<Double> entryRange : foo.entryRanges()) { 61 i += entryRange.value; 62 } 63 assertEquals("EntryRange<T>", 127d, i); 64 } 65 66 public void checkToString(UnicodeMap<Double> foo, String expected) { 67 assertEquals("EntryRange<T>", expected, CollectionUtilities.join(foo.entryRanges(), "\n") + (foo.size() == 0 ? "" : "\n")); 68 assertEquals("EntryRange<T>", expected, foo.toString()); 69 } 70 71 @Test 72 public void TestRemove() { 73 UnicodeMap<Double> foo = new UnicodeMap() 74 .putAll(0x20, 0x29, -2d) 75 .put("abc", 3d) 76 .put("xy", 2d) 77 .put("mark", 4d) 78 .freeze(); 79 UnicodeMap<Double> fii = new UnicodeMap() 80 .putAll(0x21, 0x25, -2d) 81 .putAll(0x26, 0x28, -3d) 82 .put("abc", 3d) 83 .put("mark", 999d) 84 .freeze(); 85 86 UnicodeMap<Double> afterFiiRemoval = new UnicodeMap() 87 .put(0x20, -2d) 88 .putAll(0x26, 0x29, -2d) 89 .put("xy", 2d) 90 .put("mark", 4d) 91 .freeze(); 92 93 UnicodeMap<Double> afterFiiRetained = new UnicodeMap() 94 .putAll(0x21, 0x25, -2d) 95 .put("abc", 3d) 96 .freeze(); 97 98 UnicodeMap<Double> test = new UnicodeMap<Double>().putAll(foo) 99 .removeAll(fii); 100 assertEquals("removeAll", afterFiiRemoval, test); 101 102 test = new UnicodeMap<Double>().putAll(foo) 103 .retainAll(fii); 104 assertEquals("retainAll", afterFiiRetained, test); 105 } 106 107 @Test 108 public void TestAMonkey() { 109 SortedMap<String,Integer> stayWithMe = new TreeMap<String,Integer>(OneFirstComparator); 110 111 UnicodeMap<Integer> me = new UnicodeMap<Integer>().putAll(stayWithMe); 112 // check one special case, removal near end 113 me.putAll(0x10FFFE, 0x10FFFF, 666); 114 me.remove(0x10FFFF); 115 116 int iterations = 100000; 117 SortedMap<String,Integer> test = new TreeMap(); 118 119 Random rand = new Random(0); 120 String other; 121 Integer value; 122 // try modifications 123 for (int i = 0; i < iterations ; ++i) { 124 switch(rand.nextInt(20)) { 125 case 0: 126 logln("clear"); 127 stayWithMe.clear(); 128 me.clear(); 129 break; 130 case 1: 131 fillRandomMap(rand, 5, test); 132 logln("putAll\t" + test); 133 stayWithMe.putAll(test); 134 me.putAll(test); 135 break; 136 case 2: case 3: case 4: case 5: case 6: case 7: case 8: 137 other = getRandomKey(rand); 138 // if (other.equals("\uDBFF\uDFFF") && me.containsKey(0x10FFFF) && me.get(0x10FFFF).equals(me.get(0x10FFFE))) { 139 // System.out.println("Remove\t" + other + "\n" + me); 140 // } 141 logln("remove\t" + other); 142 stayWithMe.remove(other); 143 try { 144 me.remove(other); 145 } catch (IllegalArgumentException e) { 146 errln("remove\t" + other + "\tfailed: " + e.getMessage() + "\n" + me); 147 me.clear(); 148 stayWithMe.clear(); 149 } 150 break; 151 default: 152 other = getRandomKey(rand); 153 value = rand.nextInt(50)+50; 154 logln("put\t" + other + " = " + value); 155 stayWithMe.put(other, value); 156 me.put(other,value); 157 break; 158 } 159 checkEquals(me, stayWithMe); 160 } 161 } 162 163 /** 164 * @param rand 165 * @param nextInt 166 * @param test 167 * @return 168 */ 169 private SortedMap<String, Integer> fillRandomMap(Random rand, int max, SortedMap<String, Integer> test) { 170 test.clear(); 171 max = rand.nextInt(max); 172 for (int i = 0; i < max; ++i) { 173 test.put(getRandomKey(rand), rand.nextInt(50)+50); 174 } 175 return test; 176 } 177 178 Set temp = new HashSet(); 179 /** 180 * @param me 181 * @param stayWithMe 182 */ 183 private void checkEquals(UnicodeMap<Integer> me, SortedMap<String, Integer> stayWithMe) { 184 temp.clear(); 185 for (Entry<String, Integer> e : me.entrySet()) { 186 temp.add(e); 187 } 188 Set<Entry<String, Integer>> entrySet = stayWithMe.entrySet(); 189 if (!entrySet.equals(temp)) { 190 logln(me.entrySet().toString()); 191 logln(me.toString()); 192 assertEquals("are in parallel", entrySet, temp); 193 // we failed. Reset and start again 194 entrySet.clear(); 195 temp.clear(); 196 return; 197 } 198 for (String key : stayWithMe.keySet()) { 199 assertEquals("containsKey", stayWithMe.containsKey(key), me.containsKey(key)); 200 Integer value = stayWithMe.get(key); 201 assertEquals("get", value, me.get(key)); 202 assertEquals("containsValue", stayWithMe.containsValue(value), me.containsValue(value)); 203 int cp = UnicodeSet.getSingleCodePoint(key); 204 if (cp != Integer.MAX_VALUE) { 205 assertEquals("get", value, me.get(cp)); 206 } 207 } 208 Set<String> nonCodePointStrings = stayWithMe.tailMap("").keySet(); 209 if (nonCodePointStrings.size() == 0) nonCodePointStrings = null; // for parallel api 210 assertEquals("getNonRangeStrings", nonCodePointStrings, me.getNonRangeStrings()); 211 212 TreeSet<Integer> values = new TreeSet<Integer>(stayWithMe.values()); 213 TreeSet<Integer> myValues = new TreeSet<Integer>(me.values()); 214 assertEquals("values", myValues, values); 215 216 for (String key : stayWithMe.keySet()) { 217 assertEquals("containsKey", stayWithMe.containsKey(key), me.containsKey(key)); 218 } 219 } 220 221 static Comparator<String> OneFirstComparator = new Comparator<String>() { 222 public int compare(String o1, String o2) { 223 int cp1 = UnicodeSet.getSingleCodePoint(o1); 224 int cp2 = UnicodeSet.getSingleCodePoint(o2); 225 int result = cp1 - cp2; 226 if (result != 0) { 227 return result; 228 } 229 if (cp1 == Integer.MAX_VALUE) { 230 return o1.compareTo(o2); 231 } 232 return 0; 233 } 234 235 }; 236 237 /** 238 * @param rand 239 * @param others 240 * @return 241 */ 242 private String getRandomKey(Random rand) { 243 int r = rand.nextInt(30); 244 if (r == 0) { 245 return UTF16.valueOf(r); 246 } else if (r < 10) { 247 return UTF16.valueOf('A'-1+r); 248 } else if (r < 20) { 249 return UTF16.valueOf(0x10FFFF - (r-10)); 250 // } else if (r == 20) { 251 // return ""; 252 } 253 return "a" + UTF16.valueOf(r + 'a'-1); 254 } 255 256 @Test 257 public void TestModify() { 258 Random random = new Random(0); 259 UnicodeMap unicodeMap = new UnicodeMap(); 260 HashMap hashMap = new HashMap(); 261 String[] values = {null, "the", "quick", "brown", "fox"}; 262 for (int count = 1; count <= MODIFY_TEST_ITERATIONS; ++count) { 263 String value = values[random.nextInt(values.length)]; 264 int start = random.nextInt(MODIFY_TEST_LIMIT); // test limited range 265 int end = random.nextInt(MODIFY_TEST_LIMIT); 266 if (start > end) { 267 int temp = start; 268 start = end; 269 end = temp; 270 } 271 int modCount = count & 0xFF; 272 if (modCount == 0 && isVerbose()) { 273 logln("***"+count); 274 logln(unicodeMap.toString()); 275 } 276 unicodeMap.putAll(start, end, value); 277 if (modCount == 1 && isVerbose()) { 278 logln(">>>\t" + Utility.hex(start) + ".." + Utility.hex(end) + "\t" + value); 279 logln(unicodeMap.toString()); 280 } 281 for (int i = start; i <= end; ++i) { 282 hashMap.put(new Integer(i), value); 283 } 284 if (!hasSameValues(unicodeMap, hashMap)) { 285 errln("Failed at " + count); 286 } 287 } 288 } 289 290 private boolean hasSameValues(UnicodeMap unicodeMap, HashMap hashMap) { 291 for (int i = 0; i < MODIFY_TEST_LIMIT; ++i) { 292 Object unicodeMapValue = unicodeMap.getValue(i); 293 Object hashMapValue = hashMap.get(new Integer(i)); 294 if (unicodeMapValue != hashMapValue) { 295 return false; 296 } 297 } 298 return true; 299 } 300 301 @Test 302 public void TestCloneAsThawed11721 () { 303 UnicodeMap<Integer> test = new UnicodeMap().put("abc", 3).freeze(); 304 UnicodeMap<Integer> copy = test.cloneAsThawed(); 305 copy.put("def", 4); 306 assertEquals("original-abc", (Integer) 3, test.get("abc")); 307 assertNull("original-def", test.get("def")); 308 assertEquals("copy-def", (Integer) 4, copy.get("def")); 309 } 310 311 private static final int LIMIT = 0x15; // limit to make testing more realistic in terms of collisions 312 private static final int ITERATIONS = 1000000; 313 private static final boolean SHOW_PROGRESS = false; 314 private static final boolean DEBUG = false; 315 316 SortedSet<String> log = new TreeSet<String>(); 317 static String[] TEST_VALUES = {"A", "B", "C", "D", "E", "F"}; 318 static Random random = new Random(12345); 319 320 public void TestUnicodeMapRandom() { 321 // do random change to both, then compare 322 random.setSeed(12345); // reproducible results 323 logln("Comparing against HashMap"); 324 UnicodeMap<String> map1 = new UnicodeMap(); 325 Map<Integer, String> map2 = new HashMap<Integer, String>(); 326 for (int counter = 0; counter < ITERATIONS; ++counter) { 327 int start = random.nextInt(LIMIT); 328 String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)]; 329 String logline = Utility.hex(start) + "\t" + value; 330 if (SHOW_PROGRESS) logln(counter + "\t" + logline); 331 log.add(logline); 332 if (DEBUG && counter == 144) { 333 System.out.println(" debug"); 334 } 335 map1.put(start, value); 336 map2.put(start, value); 337 check(map1, map2, counter); 338 } 339 checkNext(map1, map2, LIMIT); 340 } 341 342 private static final int SET_LIMIT = 0x10FFFF; 343 private static final int propEnum = UProperty.GENERAL_CATEGORY; 344 345 public void TestUnicodeMapGeneralCategory() { 346 logln("Setting General Category"); 347 UnicodeMap<String> map1 = new UnicodeMap(); 348 Map<Integer, String> map2 = new HashMap<Integer, String>(); 349 //Map<Integer, String> map3 = new TreeMap<Integer, String>(); 350 map1 = new UnicodeMap<String>(); 351 map2 = new TreeMap<Integer,String>(); 352 for (int cp = 0; cp <= SET_LIMIT; ++cp) { 353 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); 354 //if (enumValue <= 0) continue; // for smaller set 355 String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); 356 map1.put(cp, value); 357 map2.put(cp, value); 358 } 359 checkNext(map1, map2, Integer.MAX_VALUE); 360 361 logln("Comparing General Category"); 362 check(map1, map2, -1); 363 logln("Comparing Values"); 364 Set<String> values1 = map1.getAvailableValues(new TreeSet<String>()); 365 Set<String> values2 = new TreeSet<String>(map2.values()); 366 if (!TestBoilerplate.verifySetsIdentical(this, values1, values2)) { 367 throw new IllegalArgumentException("Halting"); 368 } 369 logln("Comparing Sets"); 370 for (Iterator<String> it = values1.iterator(); it.hasNext();) { 371 String value = it.next(); 372 logln(value == null ? "null" : value); 373 UnicodeSet set1 = map1.keySet(value); 374 UnicodeSet set2 = TestBoilerplate.getSet(map2, value); 375 if (!TestBoilerplate.verifySetsIdentical(this, set1, set2)) { 376 throw new IllegalArgumentException("Halting"); 377 } 378 } 379 } 380 381 public void TestAUnicodeMap2() { 382 UnicodeMap foo = new UnicodeMap(); 383 @SuppressWarnings("unused") 384 int hash = foo.hashCode(); // make sure doesn't NPE 385 @SuppressWarnings("unused") 386 Set fii = foo.stringKeys(); // make sure doesn't NPE 387 } 388 389 public void TestAUnicodeMapInverse() { 390 UnicodeMap<Character> foo1 = new UnicodeMap<Character>() 391 .putAll('a', 'z', 'b') 392 .put("ab", 'c') 393 .put('x', 'b') 394 .put("xy", 'c') 395 ; 396 Map<Character, UnicodeSet> target = new HashMap<Character, UnicodeSet>(); 397 foo1.addInverseTo(target); 398 UnicodeMap<Character> reverse = new UnicodeMap().putAllInverse(target); 399 assertEquals("", foo1, reverse); 400 } 401 402 private void checkNext(UnicodeMap<String> map1, Map<Integer,String> map2, int limit) { 403 logln("Comparing nextRange"); 404 Map localMap = new TreeMap(); 405 UnicodeMapIterator<String> mi = new UnicodeMapIterator<String>(map1); 406 while (mi.nextRange()) { 407 logln(Utility.hex(mi.codepoint) + ".." + Utility.hex(mi.codepointEnd) + " => " + mi.value); 408 for (int i = mi.codepoint; i <= mi.codepointEnd; ++i) { 409 //if (i >= limit) continue; 410 localMap.put(i, mi.value); 411 } 412 } 413 checkMap(map2, localMap); 414 415 logln("Comparing next"); 416 mi.reset(); 417 localMap = new TreeMap(); 418 // String lastValue = null; 419 while (mi.next()) { 420 // if (!UnicodeMap.areEqual(lastValue, mi.value)) { 421 // // System.out.println("Change: " + Utility.hex(mi.codepoint) + " => " + mi.value); 422 // lastValue = mi.value; 423 // } 424 //if (mi.codepoint >= limit) continue; 425 localMap.put(mi.codepoint, mi.value); 426 } 427 checkMap(map2, localMap); 428 } 429 430 public void check(UnicodeMap<String> map1, Map<Integer,String> map2, int counter) { 431 for (int i = 0; i < LIMIT; ++i) { 432 String value1 = map1.getValue(i); 433 String value2 = map2.get(i); 434 if (!UnicodeMap.areEqual(value1, value2)) { 435 errln(counter + " Difference at " + Utility.hex(i) 436 + "\t UnicodeMap: " + value1 437 + "\t HashMap: " + value2); 438 errln("UnicodeMap: " + map1); 439 errln("Log: " + TestBoilerplate.show(log)); 440 errln("HashMap: " + TestBoilerplate.show(map2)); 441 } 442 } 443 } 444 445 void checkMap(Map m1, Map m2) { 446 if (m1.equals(m2)) return; 447 StringBuilder buffer = new StringBuilder(); 448 Set m1entries = m1.entrySet(); 449 Set m2entries = m2.entrySet(); 450 getEntries("\r\nIn First, and not Second", m1entries, m2entries, buffer, 20); 451 getEntries("\r\nIn Second, and not First", m2entries, m1entries, buffer, 20); 452 errln(buffer.toString()); 453 } 454 455 static Comparator<Map.Entry<Integer, String>> ENTRY_COMPARATOR = new Comparator<Map.Entry<Integer, String>>() { 456 public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) { 457 if (o1 == o2) return 0; 458 if (o1 == null) return -1; 459 if (o2 == null) return 1; 460 Map.Entry<Integer, String> a = o1; 461 Map.Entry<Integer, String> b = o2; 462 int result = compare2(a.getKey(), b.getKey()); 463 if (result != 0) return result; 464 return compare2(a.getValue(), b.getValue()); 465 } 466 private <T extends Comparable> int compare2(T o1, T o2) { 467 if (o1 == o2) return 0; 468 if (o1 == null) return -1; 469 if (o2 == null) return 1; 470 return o1.compareTo(o2); 471 } 472 }; 473 474 private void getEntries(String title, Set<Map.Entry<Integer,String>> m1entries, Set<Map.Entry<Integer, String>> m2entries, StringBuilder buffer, int limit) { 475 Set<Map.Entry<Integer, String>> m1_m2 = new TreeSet<Map.Entry<Integer, String>>(ENTRY_COMPARATOR); 476 m1_m2.addAll(m1entries); 477 m1_m2.removeAll(m2entries); 478 buffer.append(title + ": " + m1_m2.size() + "\r\n"); 479 for (Entry<Integer, String> entry : m1_m2) { 480 if (limit-- < 0) return; 481 buffer.append(entry.getKey()).append(" => ") 482 .append(entry.getValue()).append("\r\n"); 483 } 484 } 485 } 486