1a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev/* 2a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Copyright (C) 2015 The Android Open Source Project 3a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 4a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Licensed under the Apache License, Version 2.0 (the "License"); 5a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * you may not use this file except in compliance with the License. 6a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * You may obtain a copy of the License at 7a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 8a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * http://www.apache.org/licenses/LICENSE-2.0 9a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 10a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Unless required by applicable law or agreed to in writing, software 11a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * distributed under the License is distributed on an "AS IS" BASIS, 12a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * See the License for the specific language governing permissions and 14a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * limitations under the License. 15a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev */ 16a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 17a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevpackage android.support.v7.util; 18a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 19a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport static org.hamcrest.MatcherAssert.*; 20a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport static org.hamcrest.CoreMatchers.*; 21a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 22a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport org.junit.Before; 23a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport org.junit.Test; 24a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport org.junit.runner.RunWith; 25a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 26a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport android.os.Looper; 27a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport android.support.test.runner.AndroidJUnit4; 28a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 29a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.HashMap; 30a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.Map; 31a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.concurrent.Semaphore; 32a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.concurrent.TimeUnit; 33a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 34a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev@RunWith(AndroidJUnit4.class) 35a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevpublic class ThreadUtilTest { 36a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Map<String, LockedObject> results = new HashMap<>(); 37a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 38a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev ThreadUtil.MainThreadCallback<Integer> mMainThreadProxy; 39a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev ThreadUtil.BackgroundCallback<Integer> mBackgroundProxy; 40a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 41a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Before 42a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void setup() { 43a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev ThreadUtil<Integer> threadUtil = new MessageThreadUtil<>(); 44a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 45a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mMainThreadProxy = threadUtil.getMainThreadProxy( 46a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev new ThreadUtil.MainThreadCallback<Integer>() { 47a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 48a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void updateItemCount(int generation, int itemCount) { 49a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertMainThread(); 50a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("updateItemCount", generation, itemCount); 51a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 52a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 53a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 54a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void addTile(int generation, TileList.Tile<Integer> data) { 55a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertMainThread(); 56a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("addTile", generation, data); 57a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 58a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 59a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 60a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void removeTile(int generation, int position) { 61a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertMainThread(); 62a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("removeTile", generation, position); 63a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 64a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev }); 65a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 66a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mBackgroundProxy = threadUtil.getBackgroundProxy( 67a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev new ThreadUtil.BackgroundCallback<Integer>() { 68a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 69a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void refresh(int generation) { 70a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertBackgroundThread(); 71a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("refresh", generation); 72a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 73a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 74a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 75a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void updateRange(int rangeStart, int rangeEnd, int extRangeStart, 76a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int extRangeEnd, int scrollHint) { 77a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertBackgroundThread(); 78a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("updateRange", rangeStart, rangeEnd, 79a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev extRangeStart, extRangeEnd, scrollHint); 80a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 81a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 82a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 83a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void loadTile(int position, int scrollHint) { 84a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertBackgroundThread(); 85a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("loadTile", position, scrollHint); 86a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 87a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 88a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 89a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void recycleTile(TileList.Tile<Integer> data) { 90a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertBackgroundThread(); 91a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev setResultData("recycleTile", data); 92a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 93a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev }); 94a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 95a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 96a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 97a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testUpdateItemCount() throws InterruptedException { 98a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("updateItemCount"); 99a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mMainThreadProxy.updateItemCount(7, 9); 100a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("updateItemCount"); 101a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{7, 9})); 102a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 103a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 104a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 105a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testAddTile() throws InterruptedException { 106a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("addTile"); 107a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10); 108a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mMainThreadProxy.addTile(3, tile); 109a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("addTile"); 110a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{3, tile})); 111a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 112a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 113a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 114a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testRemoveTile() throws InterruptedException { 115a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("removeTile"); 116a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mMainThreadProxy.removeTile(1, 2); 117a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("removeTile"); 118a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{1, 2})); 119a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 120a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 121a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 122a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testRefresh() throws InterruptedException { 123a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("refresh"); 124a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mBackgroundProxy.refresh(2); 125a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("refresh"); 126a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{2})); 127a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 128a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 129a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 130a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testRangeUpdate() throws InterruptedException { 131a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("updateRange"); 132a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mBackgroundProxy.updateRange(10, 20, 5, 25, 1); 133a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("updateRange"); 134a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[] {10, 20, 5, 25, 1})); 135a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 136a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 137a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 138a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testLoadTile() throws InterruptedException { 139a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("loadTile"); 140a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mBackgroundProxy.loadTile(2, 1); 141a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("loadTile"); 142a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{2, 1})); 143a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 144a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 145a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Test 146a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void testRecycleTile() throws InterruptedException { 147a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev initWait("recycleTile"); 148a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10); 149a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mBackgroundProxy.recycleTile(tile); 150a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev Object[] data = waitFor("recycleTile"); 151a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(data, is(new Object[]{tile})); 152a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 153a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 154a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void assertMainThread() { 155a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(Looper.myLooper(), notNullValue()); 156a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(Looper.myLooper(), sameInstance(Looper.getMainLooper())); 157a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 158a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 159a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void assertBackgroundThread() { 160a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertThat(Looper.myLooper(), not(Looper.getMainLooper())); 161a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 162a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 163a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void initWait(String key) throws InterruptedException { 164a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev results.put(key, new LockedObject()); 165a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 166a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 167a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private Object[] waitFor(String key) throws InterruptedException { 168a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return results.get(key).waitFor(); 169a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 170a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 171a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void setResultData(String key, Object... args) { 172a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (results.containsKey(key)) { 173a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev results.get(key).set(args); 174a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 175a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 176a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 177a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private class LockedObject { 178a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private Semaphore mLock = new Semaphore(1); 179a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private volatile Object[] mArgs; 180a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 181a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public LockedObject() { 182a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLock.drainPermits(); 183a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 184a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 185a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void set(Object... args) { 186a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mArgs = args; 187a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLock.release(1); 188a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 189a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 190a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public Object[] waitFor() throws InterruptedException { 191a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLock.tryAcquire(1, 2, TimeUnit.SECONDS); 192a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return mArgs; 193a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 194a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 195a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev} 196