Home | History | Annotate | Download | only in activity
      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