1/* 2 * Copyright 2018 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 17package androidx.collection; 18 19import static org.junit.Assert.fail; 20 21import org.junit.Test; 22 23import java.util.ConcurrentModificationException; 24import java.util.Locale; 25 26/** 27 * Unit tests for SimpleArrayMap 28 */ 29public class SimpleArrayMapTest { 30 SimpleArrayMap<String, String> map = new SimpleArrayMap<>(); 31 private boolean mDone; 32 33 /** 34 * Attempt to generate a ConcurrentModificationException in ArrayMap. 35 */ 36 @Test 37 public void testConcurrentModificationException() throws Exception { 38 final int TEST_LEN_MS = 5000; 39 System.out.println("Starting SimpleArrayMap concurrency test"); 40 mDone = false; 41 new Thread(new Runnable() { 42 @Override 43 public void run() { 44 int i = 0; 45 while (!mDone) { 46 try { 47 map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT"); 48 } catch (ArrayIndexOutOfBoundsException e) { 49 // SimpleArrayMap is not thread safe, so lots of concurrent modifications 50 // can still cause data corruption 51 System.err.println("concurrent modification uncaught, causing indexing failure"); 52 e.printStackTrace(); 53 } catch (ClassCastException e) { 54 // cache corruption should not occur as it is hard to trace and one thread 55 // may corrupt the pool for all threads in the same process. 56 System.err.println("concurrent modification uncaught, causing cache corruption"); 57 e.printStackTrace(); 58 fail(); 59 } catch (ConcurrentModificationException e) { 60 } 61 } 62 } 63 }).start(); 64 for (int i = 0; i < (TEST_LEN_MS / 100); i++) { 65 try { 66 Thread.sleep(100); 67 map.clear(); 68 } catch (InterruptedException e) { 69 } catch (ArrayIndexOutOfBoundsException e) { 70 System.err.println("concurrent modification uncaught, causing indexing failure"); 71 } catch (ClassCastException e) { 72 System.err.println("concurrent modification uncaught, causing cache corruption"); 73 fail(); 74 } catch (ConcurrentModificationException e) { 75 } 76 } 77 mDone = true; 78 } 79 80 /** 81 * Check to make sure the same operations behave as expected in a single thread. 82 */ 83 @Test 84 public void testNonConcurrentAccesses() throws Exception { 85 for (int i = 0; i < 100000; i++) { 86 try { 87 map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT"); 88 if (i % 500 == 0) { 89 map.clear(); 90 } 91 } catch (ConcurrentModificationException e) { 92 System.err.println("Concurrent modification caught on single thread"); 93 e.printStackTrace(); 94 fail(); 95 } 96 } 97 } 98} 99