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