1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.test.activity; 18 19 import android.util.ArrayMap; 20 import android.util.ArraySet; 21 import android.util.Log; 22 23 import java.util.Collection; 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.Iterator; 27 import java.util.Map; 28 import java.util.Set; 29 30 public class ArrayMapTests { 31 static final int OP_ADD = 1; 32 static final int OP_REM = 2; 33 34 static int[] OPS = new int[] { 35 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 36 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 37 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 38 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 39 40 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 41 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 42 43 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 44 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 45 46 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 47 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 48 49 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 50 OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, 51 OP_ADD, OP_ADD, OP_ADD, 52 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 53 OP_REM, OP_REM, OP_REM, 54 OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, 55 }; 56 57 static int[] KEYS = new int[] { 58 // General adding and removing. 59 -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900, 60 2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400, 61 600, -1, 1900, 600, 300, 2100, 200, 800, 800, 62 1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900, 63 64 // Shrink when removing item from end. 65 100, 200, 300, 400, 500, 600, 700, 800, 900, 66 900, 800, 700, 600, 500, 400, 300, 200, 100, 67 68 // Shrink when removing item from middle. 69 100, 200, 300, 400, 500, 600, 700, 800, 900, 70 900, 800, 700, 600, 500, 400, 200, 300, 100, 71 72 // Shrink when removing item from front. 73 100, 200, 300, 400, 500, 600, 700, 800, 900, 74 900, 800, 700, 600, 500, 400, 100, 200, 300, 75 76 // Test hash collisions. 77 105, 106, 108, 104, 102, 102, 107, 5, 205, 78 4, 202, 203, 3, 5, 101, 109, 200, 201, 79 0, -1, 100, 80 106, 108, 104, 102, 103, 105, 107, 101, 109, 81 -1, 100, 0, 82 4, 5, 3, 5, 200, 203, 202, 201, 205, 83 }; 84 85 static class ControlledHash { 86 final int mValue; 87 88 ControlledHash(int value) { 89 mValue = value; 90 } 91 92 @Override 93 public final boolean equals(Object o) { 94 if (o == null) { 95 return false; 96 } 97 return mValue == ((ControlledHash)o).mValue; 98 } 99 100 @Override 101 public final int hashCode() { 102 return mValue/100; 103 } 104 105 @Override 106 public final String toString() { 107 return Integer.toString(mValue); 108 } 109 } 110 111 private static boolean compare(Object v1, Object v2) { 112 if (v1 == null) { 113 return v2 == null; 114 } 115 if (v2 == null) { 116 return false; 117 } 118 return v1.equals(v2); 119 } 120 121 private static boolean compareMaps(HashMap map, ArrayMap array) { 122 if (map.size() != array.size()) { 123 Log.e("test", "Bad size: expected " + map.size() + ", got " + array.size()); 124 return false; 125 } 126 127 Set<Map.Entry> mapSet = map.entrySet(); 128 for (Map.Entry entry : mapSet) { 129 Object expValue = entry.getValue(); 130 Object gotValue = array.get(entry.getKey()); 131 if (!compare(expValue, gotValue)) { 132 Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue 133 + " at key " + entry.getKey()); 134 return false; 135 } 136 } 137 138 for (int i=0; i<array.size(); i++) { 139 Object gotValue = array.valueAt(i); 140 Object key = array.keyAt(i); 141 Object expValue = map.get(key); 142 if (!compare(expValue, gotValue)) { 143 Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue 144 + " at key " + key); 145 return false; 146 } 147 } 148 149 if (map.entrySet().hashCode() != array.entrySet().hashCode()) { 150 Log.e("test", "Entry set hash codes differ: map=0x" 151 + Integer.toHexString(map.entrySet().hashCode()) + " array=0x" 152 + Integer.toHexString(array.entrySet().hashCode())); 153 return false; 154 } 155 156 if (!map.entrySet().equals(array.entrySet())) { 157 Log.e("test", "Failed calling equals on map entry set against array set"); 158 return false; 159 } 160 161 if (!array.entrySet().equals(map.entrySet())) { 162 Log.e("test", "Failed calling equals on array entry set against map set"); 163 return false; 164 } 165 166 if (map.keySet().hashCode() != array.keySet().hashCode()) { 167 Log.e("test", "Key set hash codes differ: map=0x" 168 + Integer.toHexString(map.keySet().hashCode()) + " array=0x" 169 + Integer.toHexString(array.keySet().hashCode())); 170 return false; 171 } 172 173 if (!map.keySet().equals(array.keySet())) { 174 Log.e("test", "Failed calling equals on map key set against array set"); 175 return false; 176 } 177 178 if (!array.keySet().equals(map.keySet())) { 179 Log.e("test", "Failed calling equals on array key set against map set"); 180 return false; 181 } 182 183 if (!map.keySet().containsAll(array.keySet())) { 184 Log.e("test", "Failed map key set contains all of array key set"); 185 return false; 186 } 187 188 if (!array.keySet().containsAll(map.keySet())) { 189 Log.e("test", "Failed array key set contains all of map key set"); 190 return false; 191 } 192 193 if (!array.containsAll(map.keySet())) { 194 Log.e("test", "Failed array contains all of map key set"); 195 return false; 196 } 197 198 if (!map.entrySet().containsAll(array.entrySet())) { 199 Log.e("test", "Failed map entry set contains all of array entry set"); 200 return false; 201 } 202 203 if (!array.entrySet().containsAll(map.entrySet())) { 204 Log.e("test", "Failed array entry set contains all of map entry set"); 205 return false; 206 } 207 208 return true; 209 } 210 211 private static boolean compareSets(HashSet set, ArraySet array) { 212 if (set.size() != array.size()) { 213 Log.e("test", "Bad size: expected " + set.size() + ", got " + array.size()); 214 return false; 215 } 216 217 for (Object entry : set) { 218 if (!array.contains(entry)) { 219 Log.e("test", "Bad value: expected " + entry + " not found in ArraySet"); 220 return false; 221 } 222 } 223 224 for (int i=0; i<array.size(); i++) { 225 Object entry = array.valueAt(i); 226 if (!set.contains(entry)) { 227 Log.e("test", "Bad value: unexpected " + entry + " in ArraySet"); 228 return false; 229 } 230 } 231 232 int index = 0; 233 for (Object entry : array) { 234 Object realEntry = array.valueAt(index); 235 if (!compare(entry, realEntry)) { 236 Log.e("test", "Bad iterator: expected value " + realEntry + ", got " + entry 237 + " at index " + index); 238 return false; 239 } 240 index++; 241 } 242 243 return true; 244 } 245 246 private static boolean validateArrayMap(ArrayMap array) { 247 Set<Map.Entry> entrySet = array.entrySet(); 248 int index=0; 249 Iterator<Map.Entry> entryIt = entrySet.iterator(); 250 while (entryIt.hasNext()) { 251 Map.Entry entry = entryIt.next(); 252 Object value = entry.getKey(); 253 Object realValue = array.keyAt(index); 254 if (!compare(realValue, value)) { 255 Log.e("test", "Bad array map entry set: expected key " + realValue 256 + ", got " + value + " at index " + index); 257 return false; 258 } 259 value = entry.getValue(); 260 realValue = array.valueAt(index); 261 if (!compare(realValue, value)) { 262 Log.e("test", "Bad array map entry set: expected value " + realValue 263 + ", got " + value + " at index " + index); 264 return false; 265 } 266 index++; 267 } 268 269 index = 0; 270 Set keySet = array.keySet(); 271 Iterator keyIt = keySet.iterator(); 272 while (keyIt.hasNext()) { 273 Object value = keyIt.next(); 274 Object realValue = array.keyAt(index); 275 if (!compare(realValue, value)) { 276 Log.e("test", "Bad array map key set: expected key " + realValue 277 + ", got " + value + " at index " + index); 278 return false; 279 } 280 index++; 281 } 282 283 index = 0; 284 Collection valueCol = array.values(); 285 Iterator valueIt = valueCol.iterator(); 286 while (valueIt.hasNext()) { 287 Object value = valueIt.next(); 288 Object realValue = array.valueAt(index); 289 if (!compare(realValue, value)) { 290 Log.e("test", "Bad array map value col: expected value " + realValue 291 + ", got " + value + " at index " + index); 292 return false; 293 } 294 index++; 295 } 296 297 return true; 298 } 299 300 private static void dump(Map map, ArrayMap array) { 301 Log.e("test", "HashMap of " + map.size() + " entries:"); 302 Set<Map.Entry> mapSet = map.entrySet(); 303 for (Map.Entry entry : mapSet) { 304 Log.e("test", " " + entry.getKey() + " -> " + entry.getValue()); 305 } 306 Log.e("test", "ArrayMap of " + array.size() + " entries:"); 307 for (int i=0; i<array.size(); i++) { 308 Log.e("test", " " + array.keyAt(i) + " -> " + array.valueAt(i)); 309 } 310 } 311 312 private static void dump(Set set, ArraySet array) { 313 Log.e("test", "HashSet of " + set.size() + " entries:"); 314 for (Object entry : set) { 315 Log.e("test", " " + entry); 316 } 317 Log.e("test", "ArraySet of " + array.size() + " entries:"); 318 for (int i=0; i<array.size(); i++) { 319 Log.e("test", " " + array.valueAt(i)); 320 } 321 } 322 323 private static void dump(ArrayMap map1, ArrayMap map2) { 324 Log.e("test", "ArrayMap of " + map1.size() + " entries:"); 325 Set<Map.Entry> mapSet = map1.entrySet(); 326 for (int i=0; i<map2.size(); i++) { 327 Log.e("test", " " + map1.keyAt(i) + " -> " + map1.valueAt(i)); 328 } 329 Log.e("test", "ArrayMap of " + map2.size() + " entries:"); 330 for (int i=0; i<map2.size(); i++) { 331 Log.e("test", " " + map2.keyAt(i) + " -> " + map2.valueAt(i)); 332 } 333 } 334 335 public static void run() { 336 HashMap<ControlledHash, Integer> hashMap = new HashMap<ControlledHash, Integer>(); 337 ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<ControlledHash, Integer>(); 338 HashSet<ControlledHash> hashSet = new HashSet<ControlledHash>(); 339 ArraySet<ControlledHash> arraySet = new ArraySet<ControlledHash>(); 340 341 for (int i=0; i<OPS.length; i++) { 342 Integer oldHash; 343 Integer oldArray; 344 boolean hashChanged; 345 boolean arrayChanged; 346 ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]); 347 switch (OPS[i]) { 348 case OP_ADD: 349 Log.i("test", "Adding key: " + KEYS[i]); 350 oldHash = hashMap.put(key, i); 351 oldArray = arrayMap.put(key, i); 352 hashChanged = hashSet.add(key); 353 arrayChanged = arraySet.add(key); 354 break; 355 case OP_REM: 356 Log.i("test", "Removing key: " + KEYS[i]); 357 oldHash = hashMap.remove(key); 358 oldArray = arrayMap.remove(key); 359 hashChanged = hashSet.remove(key); 360 arrayChanged = arraySet.remove(key); 361 break; 362 default: 363 Log.e("test", "Bad operation " + OPS[i] + " @ " + i); 364 return; 365 } 366 if (!compare(oldHash, oldArray)) { 367 Log.e("test", "Bad result: expected " + oldHash + ", got " + oldArray); 368 dump(hashMap, arrayMap); 369 return; 370 } 371 if (hashChanged != arrayChanged) { 372 Log.e("test", "Bad change: expected " + hashChanged + ", got " + arrayChanged); 373 dump(hashSet, arraySet); 374 return; 375 } 376 if (!validateArrayMap(arrayMap)) { 377 dump(hashMap, arrayMap); 378 return; 379 } 380 if (!compareMaps(hashMap, arrayMap)) { 381 dump(hashMap, arrayMap); 382 return; 383 } 384 if (!compareSets(hashSet, arraySet)) { 385 dump(hashSet, arraySet); 386 return; 387 } 388 } 389 390 arrayMap.put(new ControlledHash(50000), 100); 391 ControlledHash lookup = new ControlledHash(50000); 392 Iterator<ControlledHash> it = arrayMap.keySet().iterator(); 393 while (it.hasNext()) { 394 if (it.next().equals(lookup)) { 395 it.remove(); 396 } 397 } 398 if (arrayMap.containsKey(lookup)) { 399 Log.e("test", "Bad map iterator: didn't remove test key"); 400 dump(hashMap, arrayMap); 401 } 402 403 arraySet.add(new ControlledHash(50000)); 404 it = arraySet.iterator(); 405 while (it.hasNext()) { 406 if (it.next().equals(lookup)) { 407 it.remove(); 408 } 409 } 410 if (arraySet.contains(lookup)) { 411 Log.e("test", "Bad set iterator: didn't remove test key"); 412 dump(hashSet, arraySet); 413 } 414 415 if (!equalsMapTest()) { 416 return; 417 } 418 419 if (!equalsSetTest()) { 420 return; 421 } 422 423 // map copy constructor test 424 ArrayMap newMap = new ArrayMap<Integer, String>(); 425 for (int i = 0; i < 10; ++i) { 426 newMap.put(i, String.valueOf(i)); 427 } 428 ArrayMap mapCopy = new ArrayMap(newMap); 429 if (!compare(mapCopy, newMap)) { 430 Log.e("test", "ArrayMap copy constructor failure: expected " + 431 newMap + ", got " + mapCopy); 432 dump(newMap, mapCopy); 433 return; 434 } 435 436 // set copy constructor test 437 ArraySet newSet = new ArraySet<Integer>(); 438 for (int i = 0; i < 10; ++i) { 439 newSet.add(i); 440 } 441 ArraySet setCopy = new ArraySet(newSet); 442 if (!compare(setCopy, newSet)) { 443 Log.e("test", "ArraySet copy constructor failure: expected " + 444 newSet + ", got " + setCopy); 445 dump(newSet, setCopy); 446 return; 447 } 448 449 Log.e("test", "Test successful; printing final map."); 450 dump(hashMap, arrayMap); 451 452 Log.e("test", "Test successful; printing final set."); 453 dump(hashSet, arraySet); 454 } 455 456 private static boolean equalsMapTest() { 457 ArrayMap<Integer, String> map1 = new ArrayMap<Integer, String>(); 458 ArrayMap<Integer, String> map2 = new ArrayMap<Integer, String>(); 459 HashMap<Integer, String> map3 = new HashMap<Integer, String>(); 460 if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) { 461 Log.e("test", "ArrayMap equals failure for empty maps " + map1 + ", " + 462 map2 + ", " + map3); 463 return false; 464 } 465 466 for (int i = 0; i < 10; ++i) { 467 String value = String.valueOf(i); 468 map1.put(i, value); 469 map2.put(i, value); 470 map3.put(i, value); 471 } 472 if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) { 473 Log.e("test", "ArrayMap equals failure for populated maps " + map1 + ", " + 474 map2 + ", " + map3); 475 return false; 476 } 477 478 map1.remove(0); 479 if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) { 480 Log.e("test", "ArrayMap equals failure for map size " + map1 + ", " + 481 map2 + ", " + map3); 482 return false; 483 } 484 485 map1.put(0, "-1"); 486 if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) { 487 Log.e("test", "ArrayMap equals failure for map contents " + map1 + ", " + 488 map2 + ", " + map3); 489 return false; 490 } 491 492 return true; 493 } 494 495 private static boolean equalsSetTest() { 496 ArraySet<Integer> set1 = new ArraySet<Integer>(); 497 ArraySet<Integer> set2 = new ArraySet<Integer>(); 498 HashSet<Integer> set3 = new HashSet<Integer>(); 499 if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) { 500 Log.e("test", "ArraySet equals failure for empty sets " + set1 + ", " + 501 set2 + ", " + set3); 502 return false; 503 } 504 505 for (int i = 0; i < 10; ++i) { 506 set1.add(i); 507 set2.add(i); 508 set3.add(i); 509 } 510 if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) { 511 Log.e("test", "ArraySet equals failure for populated sets " + set1 + ", " + 512 set2 + ", " + set3); 513 return false; 514 } 515 516 set1.remove(0); 517 if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) { 518 Log.e("test", "ArraSet equals failure for set size " + set1 + ", " + 519 set2 + ", " + set3); 520 return false; 521 } 522 523 set1.add(-1); 524 if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) { 525 Log.e("test", "ArraySet equals failure for set contents " + set1 + ", " + 526 set2 + ", " + set3); 527 return false; 528 } 529 530 return true; 531 } 532 } 533