1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package android.testing;
16 
17 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.assertNotEquals;
19 import static org.junit.Assert.assertTrue;
20 import static org.mockito.Matchers.any;
21 import static org.mockito.Matchers.eq;
22 import static org.mockito.Mockito.inOrder;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.never;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.test.suitebuilder.annotation.SmallTest;
34 import android.testing.TestableLooper.MessageHandler;
35 import android.testing.TestableLooper.RunWithLooper;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.mockito.InOrder;
41 
42 @SmallTest
43 @RunWith(AndroidTestingRunner.class)
44 @RunWithLooper
45 public class TestableLooperTest {
46 
47     private TestableLooper mTestableLooper;
48 
49     @Before
setup()50     public void setup() throws Exception {
51         mTestableLooper = TestableLooper.get(this);
52     }
53 
54     @Test
testMessageExecuted()55     public void testMessageExecuted() throws Exception {
56         Handler h = new Handler();
57         Runnable r = mock(Runnable.class);
58         h.post(r);
59         verify(r, never()).run();
60         mTestableLooper.processAllMessages();
61         verify(r).run();
62     }
63 
64     @Test
testMessageCallback()65     public void testMessageCallback() throws Exception {
66         Handler h = new Handler();
67         Message m = h.obtainMessage(3);
68         Runnable r = mock(Runnable.class);
69         MessageHandler messageHandler = mock(MessageHandler.class);
70         when(messageHandler.onMessageHandled(any())).thenReturn(false);
71         mTestableLooper.setMessageHandler(messageHandler);
72 
73         m.sendToTarget();
74         h.post(r);
75 
76         mTestableLooper.processAllMessages();
77 
78         verify(messageHandler).onMessageHandled(eq(m));
79         // This should never be run becaus the mock returns false on the first message, and
80         // the second will get skipped.
81         verify(r, never()).run();
82     }
83 
84     @Test
testProcessNumberOfMessages()85     public void testProcessNumberOfMessages() throws Exception {
86         Handler h = new Handler();
87         Runnable r = mock(Runnable.class);
88         h.post(r);
89         h.post(r);
90         h.post(r);
91 
92         mTestableLooper.processMessages(2);
93 
94         verify(r, times(2)).run();
95     }
96 
97     @Test
testProcessAllMessages()98     public void testProcessAllMessages() throws Exception {
99         Handler h = new Handler();
100         Runnable r = mock(Runnable.class);
101         Runnable poster = () -> h.post(r);
102         h.post(poster);
103 
104         mTestableLooper.processAllMessages();
105         verify(r).run();
106     }
107 
108     @Test
test3Chain()109     public void test3Chain() throws Exception {
110         Handler h = new Handler();
111         Runnable r = mock(Runnable.class);
112         Runnable poster = () -> h.post(r);
113         Runnable poster2 = () -> h.post(poster);
114         h.post(poster2);
115 
116         mTestableLooper.processAllMessages();
117         verify(r).run();
118     }
119 
120     @Test
testProcessAllMessages_2Messages()121     public void testProcessAllMessages_2Messages() throws Exception {
122         Handler h = new Handler();
123         Runnable r = mock(Runnable.class);
124         Runnable r2 = mock(Runnable.class);
125         h.post(r);
126         h.post(r2);
127 
128         mTestableLooper.processAllMessages();
129         verify(r).run();
130         verify(r2).run();
131     }
132 
133     @Test
testMainLooper()134     public void testMainLooper() throws Exception {
135         assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
136         Runnable r = mock(Runnable.class);
137         Runnable r2 = mock(Runnable.class);
138         TestableLooper testableLooper = new TestableLooper(Looper.getMainLooper());
139 
140         try {
141             testableLooper.setMessageHandler(m -> {
142                 if (m.getCallback() == r) return true;
143                 return false;
144             });
145             new Handler(Looper.getMainLooper()).post(r);
146             testableLooper.processAllMessages();
147 
148             verify(r).run();
149             verify(r2, never()).run();
150         } finally {
151             testableLooper.destroy();
152         }
153     }
154 
155     @Test
testNonMainLooperAnnotation()156     public void testNonMainLooperAnnotation() {
157         assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
158     }
159 
160     @Test
161     @RunWithLooper(setAsMainLooper = true)
testMainLooperAnnotation()162     public void testMainLooperAnnotation() {
163         assertEquals(Looper.myLooper(), Looper.getMainLooper());
164     }
165 
166     @Test
testCorrectLooperExecution()167     public void testCorrectLooperExecution() throws Exception {
168         boolean[] hasRun = new boolean[]{false};
169         Runnable r = () -> {
170             assertEquals("Should run on main looper", Looper.getMainLooper(), Looper.myLooper());
171             hasRun[0] = true;
172         };
173         TestableLooper testableLooper = new TestableLooper(Looper.getMainLooper());
174         try {
175             new Handler(Looper.getMainLooper()).post(r);
176             testableLooper.processAllMessages();
177 
178             assertTrue(hasRun[0]);
179         } finally {
180             testableLooper.destroy();
181         }
182     }
183 
184     @Test
testDelayedDispatchNoTimeMove()185     public void testDelayedDispatchNoTimeMove() {
186         Handler handler = spy(new Handler(mTestableLooper.getLooper()));
187         InOrder inOrder = inOrder(handler);
188 
189         final Message messageA = handler.obtainMessage(1);
190         final Message messageB = handler.obtainMessage(2);
191 
192         handler.sendMessageDelayed(messageA, 0);
193         handler.sendMessageDelayed(messageB, 0);
194 
195         mTestableLooper.processAllMessages();
196 
197         inOrder.verify(handler).dispatchMessage(messageA);
198         inOrder.verify(handler).dispatchMessage(messageB);
199     }
200 
201     @Test
testDelayedMessageDoesntSend()202     public void testDelayedMessageDoesntSend() {
203         Handler handler = spy(new Handler(mTestableLooper.getLooper()));
204         InOrder inOrder = inOrder(handler);
205 
206         final Message messageA = handler.obtainMessage(1);
207         final Message messageB = handler.obtainMessage(2);
208         final Message messageC = handler.obtainMessage(3);
209 
210         handler.sendMessageDelayed(messageA, 0);
211         handler.sendMessageDelayed(messageB, 0);
212         handler.sendMessageDelayed(messageC, 500);
213 
214         mTestableLooper.processAllMessages();
215 
216         inOrder.verify(handler).dispatchMessage(messageA);
217         inOrder.verify(handler).dispatchMessage(messageB);
218         verify(handler, never()).dispatchMessage(messageC);
219     }
220 
221     @Test
testMessageSendsAfterDelay()222     public void testMessageSendsAfterDelay() {
223         Handler handler = spy(new Handler(mTestableLooper.getLooper()));
224         InOrder inOrder = inOrder(handler);
225 
226         final Message messageA = handler.obtainMessage(1);
227         final Message messageB = handler.obtainMessage(2);
228         final Message messageC = handler.obtainMessage(3);
229 
230         handler.sendMessageDelayed(messageA, 0);
231         handler.sendMessageDelayed(messageB, 0);
232         handler.sendMessageDelayed(messageC, 500);
233 
234         mTestableLooper.moveTimeForward(500);
235         mTestableLooper.processAllMessages();
236 
237         inOrder.verify(handler).dispatchMessage(messageA);
238         inOrder.verify(handler).dispatchMessage(messageB);
239         inOrder.verify(handler).dispatchMessage(messageC);
240     }
241 
242     @Test
testProcessMessagesNonBlocking_onlyArgNumber()243     public void testProcessMessagesNonBlocking_onlyArgNumber() {
244         Handler h = new Handler(mTestableLooper.getLooper());
245         Runnable r = mock(Runnable.class);
246 
247         h.post(r);
248         h.post(r);
249         h.post(r);
250 
251         int processed = mTestableLooper.processMessagesNonBlocking(2);
252 
253         verify(r, times(2)).run();
254         assertEquals(2, processed);
255     }
256 
257     @Test
testProcessMessagesNonBlocking_lessMessagesThanArg()258     public void testProcessMessagesNonBlocking_lessMessagesThanArg() {
259         Handler h = new Handler(mTestableLooper.getLooper());
260         Runnable r = mock(Runnable.class);
261 
262         h.post(r);
263         h.post(r);
264         h.post(r);
265 
266         int processed = mTestableLooper.processMessagesNonBlocking(5);
267 
268         verify(r, times(3)).run();
269         assertEquals(3, processed);
270     }
271 }
272