| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.android.test.activity; |
| |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Log; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| public class ArrayMapTests { |
| static final int OP_ADD = 1; |
| static final int OP_REM = 2; |
| |
| static int[] OPS = new int[] { |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, |
| OP_ADD, OP_ADD, OP_ADD, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| OP_REM, OP_REM, OP_REM, |
| OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, |
| }; |
| |
| static int[] KEYS = new int[] { |
| // General adding and removing. |
| -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900, |
| 2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400, |
| 600, -1, 1900, 600, 300, 2100, 200, 800, 800, |
| 1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900, |
| |
| // Shrink when removing item from end. |
| 100, 200, 300, 400, 500, 600, 700, 800, 900, |
| 900, 800, 700, 600, 500, 400, 300, 200, 100, |
| |
| // Shrink when removing item from middle. |
| 100, 200, 300, 400, 500, 600, 700, 800, 900, |
| 900, 800, 700, 600, 500, 400, 200, 300, 100, |
| |
| // Shrink when removing item from front. |
| 100, 200, 300, 400, 500, 600, 700, 800, 900, |
| 900, 800, 700, 600, 500, 400, 100, 200, 300, |
| |
| // Test hash collisions. |
| 105, 106, 108, 104, 102, 102, 107, 5, 205, |
| 4, 202, 203, 3, 5, 101, 109, 200, 201, |
| 0, -1, 100, |
| 106, 108, 104, 102, 103, 105, 107, 101, 109, |
| -1, 100, 0, |
| 4, 5, 3, 5, 200, 203, 202, 201, 205, |
| }; |
| |
| static class ControlledHash { |
| final int mValue; |
| |
| ControlledHash(int value) { |
| mValue = value; |
| } |
| |
| @Override |
| public final boolean equals(Object o) { |
| if (o == null) { |
| return false; |
| } |
| return mValue == ((ControlledHash)o).mValue; |
| } |
| |
| @Override |
| public final int hashCode() { |
| return mValue/100; |
| } |
| |
| @Override |
| public final String toString() { |
| return Integer.toString(mValue); |
| } |
| } |
| |
| private static boolean compare(Object v1, Object v2) { |
| if (v1 == null) { |
| return v2 == null; |
| } |
| if (v2 == null) { |
| return false; |
| } |
| return v1.equals(v2); |
| } |
| |
| private static boolean compareMaps(HashMap map, ArrayMap array) { |
| if (map.size() != array.size()) { |
| Log.e("test", "Bad size: expected " + map.size() + ", got " + array.size()); |
| return false; |
| } |
| |
| Set<Map.Entry> mapSet = map.entrySet(); |
| for (Map.Entry entry : mapSet) { |
| Object expValue = entry.getValue(); |
| Object gotValue = array.get(entry.getKey()); |
| if (!compare(expValue, gotValue)) { |
| Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue |
| + " at key " + entry.getKey()); |
| return false; |
| } |
| } |
| |
| for (int i=0; i<array.size(); i++) { |
| Object gotValue = array.valueAt(i); |
| Object key = array.keyAt(i); |
| Object expValue = map.get(key); |
| if (!compare(expValue, gotValue)) { |
| Log.e("test", "Bad value: expected " + expValue + ", got " + gotValue |
| + " at key " + key); |
| return false; |
| } |
| } |
| |
| if (map.entrySet().hashCode() != array.entrySet().hashCode()) { |
| Log.e("test", "Entry set hash codes differ: map=0x" |
| + Integer.toHexString(map.entrySet().hashCode()) + " array=0x" |
| + Integer.toHexString(array.entrySet().hashCode())); |
| return false; |
| } |
| |
| if (!map.entrySet().equals(array.entrySet())) { |
| Log.e("test", "Failed calling equals on map entry set against array set"); |
| return false; |
| } |
| |
| if (!array.entrySet().equals(map.entrySet())) { |
| Log.e("test", "Failed calling equals on array entry set against map set"); |
| return false; |
| } |
| |
| if (map.keySet().hashCode() != array.keySet().hashCode()) { |
| Log.e("test", "Key set hash codes differ: map=0x" |
| + Integer.toHexString(map.keySet().hashCode()) + " array=0x" |
| + Integer.toHexString(array.keySet().hashCode())); |
| return false; |
| } |
| |
| if (!map.keySet().equals(array.keySet())) { |
| Log.e("test", "Failed calling equals on map key set against array set"); |
| return false; |
| } |
| |
| if (!array.keySet().equals(map.keySet())) { |
| Log.e("test", "Failed calling equals on array key set against map set"); |
| return false; |
| } |
| |
| if (!map.keySet().containsAll(array.keySet())) { |
| Log.e("test", "Failed map key set contains all of array key set"); |
| return false; |
| } |
| |
| if (!array.keySet().containsAll(map.keySet())) { |
| Log.e("test", "Failed array key set contains all of map key set"); |
| return false; |
| } |
| |
| if (!array.containsAll(map.keySet())) { |
| Log.e("test", "Failed array contains all of map key set"); |
| return false; |
| } |
| |
| if (!map.entrySet().containsAll(array.entrySet())) { |
| Log.e("test", "Failed map entry set contains all of array entry set"); |
| return false; |
| } |
| |
| if (!array.entrySet().containsAll(map.entrySet())) { |
| Log.e("test", "Failed array entry set contains all of map entry set"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private static boolean compareSets(HashSet set, ArraySet array) { |
| if (set.size() != array.size()) { |
| Log.e("test", "Bad size: expected " + set.size() + ", got " + array.size()); |
| return false; |
| } |
| |
| for (Object entry : set) { |
| if (!array.contains(entry)) { |
| Log.e("test", "Bad value: expected " + entry + " not found in ArraySet"); |
| return false; |
| } |
| } |
| |
| for (int i=0; i<array.size(); i++) { |
| Object entry = array.valueAt(i); |
| if (!set.contains(entry)) { |
| Log.e("test", "Bad value: unexpected " + entry + " in ArraySet"); |
| return false; |
| } |
| } |
| |
| int index = 0; |
| for (Object entry : array) { |
| Object realEntry = array.valueAt(index); |
| if (!compare(entry, realEntry)) { |
| Log.e("test", "Bad iterator: expected value " + realEntry + ", got " + entry |
| + " at index " + index); |
| return false; |
| } |
| index++; |
| } |
| |
| return true; |
| } |
| |
| private static boolean validateArrayMap(ArrayMap array) { |
| Set<Map.Entry> entrySet = array.entrySet(); |
| int index=0; |
| Iterator<Map.Entry> entryIt = entrySet.iterator(); |
| while (entryIt.hasNext()) { |
| Map.Entry entry = entryIt.next(); |
| Object value = entry.getKey(); |
| Object realValue = array.keyAt(index); |
| if (!compare(realValue, value)) { |
| Log.e("test", "Bad array map entry set: expected key " + realValue |
| + ", got " + value + " at index " + index); |
| return false; |
| } |
| value = entry.getValue(); |
| realValue = array.valueAt(index); |
| if (!compare(realValue, value)) { |
| Log.e("test", "Bad array map entry set: expected value " + realValue |
| + ", got " + value + " at index " + index); |
| return false; |
| } |
| index++; |
| } |
| |
| index = 0; |
| Set keySet = array.keySet(); |
| Iterator keyIt = keySet.iterator(); |
| while (keyIt.hasNext()) { |
| Object value = keyIt.next(); |
| Object realValue = array.keyAt(index); |
| if (!compare(realValue, value)) { |
| Log.e("test", "Bad array map key set: expected key " + realValue |
| + ", got " + value + " at index " + index); |
| return false; |
| } |
| index++; |
| } |
| |
| index = 0; |
| Collection valueCol = array.values(); |
| Iterator valueIt = valueCol.iterator(); |
| while (valueIt.hasNext()) { |
| Object value = valueIt.next(); |
| Object realValue = array.valueAt(index); |
| if (!compare(realValue, value)) { |
| Log.e("test", "Bad array map value col: expected value " + realValue |
| + ", got " + value + " at index " + index); |
| return false; |
| } |
| index++; |
| } |
| |
| return true; |
| } |
| |
| private static void dump(Map map, ArrayMap array) { |
| Log.e("test", "HashMap of " + map.size() + " entries:"); |
| Set<Map.Entry> mapSet = map.entrySet(); |
| for (Map.Entry entry : mapSet) { |
| Log.e("test", " " + entry.getKey() + " -> " + entry.getValue()); |
| } |
| Log.e("test", "ArrayMap of " + array.size() + " entries:"); |
| for (int i=0; i<array.size(); i++) { |
| Log.e("test", " " + array.keyAt(i) + " -> " + array.valueAt(i)); |
| } |
| } |
| |
| private static void dump(Set set, ArraySet array) { |
| Log.e("test", "HashSet of " + set.size() + " entries:"); |
| for (Object entry : set) { |
| Log.e("test", " " + entry); |
| } |
| Log.e("test", "ArraySet of " + array.size() + " entries:"); |
| for (int i=0; i<array.size(); i++) { |
| Log.e("test", " " + array.valueAt(i)); |
| } |
| } |
| |
| private static void dump(ArrayMap map1, ArrayMap map2) { |
| Log.e("test", "ArrayMap of " + map1.size() + " entries:"); |
| Set<Map.Entry> mapSet = map1.entrySet(); |
| for (int i=0; i<map2.size(); i++) { |
| Log.e("test", " " + map1.keyAt(i) + " -> " + map1.valueAt(i)); |
| } |
| Log.e("test", "ArrayMap of " + map2.size() + " entries:"); |
| for (int i=0; i<map2.size(); i++) { |
| Log.e("test", " " + map2.keyAt(i) + " -> " + map2.valueAt(i)); |
| } |
| } |
| |
| public static void run() { |
| HashMap<ControlledHash, Integer> hashMap = new HashMap<ControlledHash, Integer>(); |
| ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<ControlledHash, Integer>(); |
| HashSet<ControlledHash> hashSet = new HashSet<ControlledHash>(); |
| ArraySet<ControlledHash> arraySet = new ArraySet<ControlledHash>(); |
| |
| for (int i=0; i<OPS.length; i++) { |
| Integer oldHash; |
| Integer oldArray; |
| boolean hashChanged; |
| boolean arrayChanged; |
| ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]); |
| switch (OPS[i]) { |
| case OP_ADD: |
| Log.i("test", "Adding key: " + KEYS[i]); |
| oldHash = hashMap.put(key, i); |
| oldArray = arrayMap.put(key, i); |
| hashChanged = hashSet.add(key); |
| arrayChanged = arraySet.add(key); |
| break; |
| case OP_REM: |
| Log.i("test", "Removing key: " + KEYS[i]); |
| oldHash = hashMap.remove(key); |
| oldArray = arrayMap.remove(key); |
| hashChanged = hashSet.remove(key); |
| arrayChanged = arraySet.remove(key); |
| break; |
| default: |
| Log.e("test", "Bad operation " + OPS[i] + " @ " + i); |
| return; |
| } |
| if (!compare(oldHash, oldArray)) { |
| Log.e("test", "Bad result: expected " + oldHash + ", got " + oldArray); |
| dump(hashMap, arrayMap); |
| return; |
| } |
| if (hashChanged != arrayChanged) { |
| Log.e("test", "Bad change: expected " + hashChanged + ", got " + arrayChanged); |
| dump(hashSet, arraySet); |
| return; |
| } |
| if (!validateArrayMap(arrayMap)) { |
| dump(hashMap, arrayMap); |
| return; |
| } |
| if (!compareMaps(hashMap, arrayMap)) { |
| dump(hashMap, arrayMap); |
| return; |
| } |
| if (!compareSets(hashSet, arraySet)) { |
| dump(hashSet, arraySet); |
| return; |
| } |
| } |
| |
| arrayMap.put(new ControlledHash(50000), 100); |
| ControlledHash lookup = new ControlledHash(50000); |
| Iterator<ControlledHash> it = arrayMap.keySet().iterator(); |
| while (it.hasNext()) { |
| if (it.next().equals(lookup)) { |
| it.remove(); |
| } |
| } |
| if (arrayMap.containsKey(lookup)) { |
| Log.e("test", "Bad map iterator: didn't remove test key"); |
| dump(hashMap, arrayMap); |
| } |
| |
| arraySet.add(new ControlledHash(50000)); |
| it = arraySet.iterator(); |
| while (it.hasNext()) { |
| if (it.next().equals(lookup)) { |
| it.remove(); |
| } |
| } |
| if (arraySet.contains(lookup)) { |
| Log.e("test", "Bad set iterator: didn't remove test key"); |
| dump(hashSet, arraySet); |
| } |
| |
| if (!equalsMapTest()) { |
| return; |
| } |
| |
| if (!equalsSetTest()) { |
| return; |
| } |
| |
| // map copy constructor test |
| ArrayMap newMap = new ArrayMap<Integer, String>(); |
| for (int i = 0; i < 10; ++i) { |
| newMap.put(i, String.valueOf(i)); |
| } |
| ArrayMap mapCopy = new ArrayMap(newMap); |
| if (!compare(mapCopy, newMap)) { |
| Log.e("test", "ArrayMap copy constructor failure: expected " + |
| newMap + ", got " + mapCopy); |
| dump(newMap, mapCopy); |
| return; |
| } |
| |
| // set copy constructor test |
| ArraySet newSet = new ArraySet<Integer>(); |
| for (int i = 0; i < 10; ++i) { |
| newSet.add(i); |
| } |
| ArraySet setCopy = new ArraySet(newSet); |
| if (!compare(setCopy, newSet)) { |
| Log.e("test", "ArraySet copy constructor failure: expected " + |
| newSet + ", got " + setCopy); |
| dump(newSet, setCopy); |
| return; |
| } |
| |
| Log.e("test", "Test successful; printing final map."); |
| dump(hashMap, arrayMap); |
| |
| Log.e("test", "Test successful; printing final set."); |
| dump(hashSet, arraySet); |
| } |
| |
| private static boolean equalsMapTest() { |
| ArrayMap<Integer, String> map1 = new ArrayMap<Integer, String>(); |
| ArrayMap<Integer, String> map2 = new ArrayMap<Integer, String>(); |
| HashMap<Integer, String> map3 = new HashMap<Integer, String>(); |
| if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) { |
| Log.e("test", "ArrayMap equals failure for empty maps " + map1 + ", " + |
| map2 + ", " + map3); |
| return false; |
| } |
| |
| for (int i = 0; i < 10; ++i) { |
| String value = String.valueOf(i); |
| map1.put(i, value); |
| map2.put(i, value); |
| map3.put(i, value); |
| } |
| if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) { |
| Log.e("test", "ArrayMap equals failure for populated maps " + map1 + ", " + |
| map2 + ", " + map3); |
| return false; |
| } |
| |
| map1.remove(0); |
| if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) { |
| Log.e("test", "ArrayMap equals failure for map size " + map1 + ", " + |
| map2 + ", " + map3); |
| return false; |
| } |
| |
| map1.put(0, "-1"); |
| if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) { |
| Log.e("test", "ArrayMap equals failure for map contents " + map1 + ", " + |
| map2 + ", " + map3); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private static boolean equalsSetTest() { |
| ArraySet<Integer> set1 = new ArraySet<Integer>(); |
| ArraySet<Integer> set2 = new ArraySet<Integer>(); |
| HashSet<Integer> set3 = new HashSet<Integer>(); |
| if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) { |
| Log.e("test", "ArraySet equals failure for empty sets " + set1 + ", " + |
| set2 + ", " + set3); |
| return false; |
| } |
| |
| for (int i = 0; i < 10; ++i) { |
| set1.add(i); |
| set2.add(i); |
| set3.add(i); |
| } |
| if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) { |
| Log.e("test", "ArraySet equals failure for populated sets " + set1 + ", " + |
| set2 + ", " + set3); |
| return false; |
| } |
| |
| set1.remove(0); |
| if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) { |
| Log.e("test", "ArraSet equals failure for set size " + set1 + ", " + |
| set2 + ", " + set3); |
| return false; |
| } |
| |
| set1.add(-1); |
| if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) { |
| Log.e("test", "ArraySet equals failure for set contents " + set1 + ", " + |
| set2 + ", " + set3); |
| return false; |
| } |
| |
| return true; |
| } |
| } |