| package com.xtremelabs.robolectric.shadows; |
| |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import com.xtremelabs.robolectric.Robolectric; |
| import com.xtremelabs.robolectric.WithTestDefaultsRunner; |
| import com.xtremelabs.robolectric.util.TestRunnable; |
| import com.xtremelabs.robolectric.util.Transcript; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import static com.xtremelabs.robolectric.Robolectric.newInstanceOf; |
| import static com.xtremelabs.robolectric.Robolectric.shadowOf; |
| import static org.hamcrest.CoreMatchers.equalTo; |
| import static org.hamcrest.CoreMatchers.nullValue; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.assertFalse; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| @RunWith(WithTestDefaultsRunner.class) |
| public class HandlerTest { |
| private Transcript transcript; |
| TestRunnable scratchRunnable = new TestRunnable(); |
| |
| private Handler.Callback callback = new Handler.Callback() { |
| @Override |
| public boolean handleMessage(Message msg) { |
| hasHandlerCallbackHandledMessage = true; |
| return false; |
| } |
| }; |
| |
| private Boolean hasHandlerCallbackHandledMessage = false; |
| |
| @Before |
| public void setUp() throws Exception { |
| transcript = new Transcript(); |
| } |
| |
| @Test |
| public void testInsertsRunnablesBasedOnLooper() throws Exception { |
| Looper looper = newInstanceOf(Looper.class); |
| |
| Handler handler1 = new Handler(looper); |
| handler1.post(new Say("first thing")); |
| |
| Handler handler2 = new Handler(looper); |
| handler2.post(new Say("second thing")); |
| |
| shadowOf(looper).idle(); |
| |
| transcript.assertEventsSoFar("first thing", "second thing"); |
| } |
| |
| @Test |
| public void testDefaultConstructorUsesDefaultLooper() throws Exception { |
| Handler handler1 = new Handler(); |
| handler1.post(new Say("first thing")); |
| |
| Handler handler2 = new Handler(Looper.myLooper()); |
| handler2.post(new Say("second thing")); |
| |
| shadowOf(Looper.myLooper()).idle(); |
| |
| transcript.assertEventsSoFar("first thing", "second thing"); |
| } |
| |
| @Test |
| public void testDifferentLoopersGetDifferentQueues() throws Exception { |
| Looper looper1 = Robolectric.newInstanceOf(Looper.class); |
| Robolectric.pauseLooper(looper1); |
| |
| Looper looper2 = Robolectric.newInstanceOf(Looper.class); |
| Robolectric.pauseLooper(looper2); |
| |
| Handler handler1 = new Handler(looper1); |
| handler1.post(new Say("first thing")); |
| |
| Handler handler2 = new Handler(looper2); |
| handler2.post(new Say("second thing")); |
| |
| shadowOf(looper2).idle(); |
| |
| transcript.assertEventsSoFar("second thing"); |
| } |
| |
| @Test |
| public void shouldCallProvidedHandlerCallback() { |
| Handler handler = new Handler(callback); |
| handler.sendMessage(new Message()); |
| assertTrue(hasHandlerCallbackHandledMessage); |
| } |
| |
| @Test |
| public void testPostAndIdleMainLooper() throws Exception { |
| new Handler().post(scratchRunnable); |
| ShadowHandler.idleMainLooper(); |
| assertThat(scratchRunnable.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void postDelayedThenIdleMainLooper_shouldNotRunRunnable() throws Exception { |
| new Handler().postDelayed(scratchRunnable, 1); |
| ShadowHandler.idleMainLooper(); |
| assertThat(scratchRunnable.wasRun, equalTo(false)); |
| } |
| |
| @Test |
| public void testPostDelayedThenRunMainLooperOneTask() throws Exception { |
| new Handler().postDelayed(scratchRunnable, 1); |
| ShadowHandler.runMainLooperOneTask(); |
| assertThat(scratchRunnable.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void testRemoveCallbacks() throws Exception { |
| Handler handler = new Handler(); |
| ShadowLooper shadowLooper = shadowOf(handler.getLooper()); |
| shadowLooper.pause(); |
| handler.post(scratchRunnable); |
| handler.removeCallbacks(scratchRunnable); |
| |
| shadowLooper.unPause(); |
| |
| assertThat(scratchRunnable.wasRun, equalTo(false)); |
| } |
| |
| @Test |
| public void testPostDelayedThenRunMainLooperToNextTask_shouldRunOneTask() throws Exception { |
| new Handler().postDelayed(scratchRunnable, 1); |
| ShadowHandler.runMainLooperToNextTask(); |
| assertThat(scratchRunnable.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void testPostDelayedTwiceThenRunMainLooperToNextTask_shouldRunMultipleTasks() throws Exception { |
| TestRunnable task1 = new TestRunnable(); |
| TestRunnable task2 = new TestRunnable(); |
| |
| new Handler().postDelayed(task1, 1); |
| new Handler().postDelayed(task2, 1); |
| |
| ShadowHandler.runMainLooperToNextTask(); |
| assertThat(task1.wasRun, equalTo(true)); |
| assertThat(task2.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void testPostDelayedTwiceThenRunMainLooperOneTask_shouldRunOnlyOneTask() throws Exception { |
| TestRunnable task1 = new TestRunnable(); |
| TestRunnable task2 = new TestRunnable(); |
| |
| new Handler().postDelayed(task1, 1); |
| new Handler().postDelayed(task2, 1); |
| |
| ShadowHandler.runMainLooperOneTask(); |
| assertThat(task1.wasRun, equalTo(true)); |
| assertThat(task2.wasRun, equalTo(false)); |
| } |
| |
| @Test |
| public void testPostDelayedMultipleThenRunMainLooperOneTask_shouldRunMultipleTask() throws Exception { |
| TestRunnable task1 = new TestRunnable(); |
| TestRunnable task2 = new TestRunnable(); |
| TestRunnable task3 = new TestRunnable(); |
| |
| new Handler().postDelayed(task1, 1); |
| new Handler().postDelayed(task2, 10); |
| new Handler().postDelayed(task3, 100); |
| |
| ShadowHandler.runMainLooperToEndOfTasks(); |
| assertThat(task1.wasRun, equalTo(true)); |
| assertThat(task2.wasRun, equalTo(true)); |
| assertThat(task3.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void testPostAtFrontOfQueueThenRunMainLooperOneTaskAtATime_shouldRunFrontOfQueueTaskFirst() throws Exception { |
| TestRunnable task1 = new TestRunnable(); |
| TestRunnable task2 = new TestRunnable(); |
| |
| ShadowLooper.pauseMainLooper(); |
| new Handler().post(task1); |
| boolean result = new Handler().postAtFrontOfQueue(task2); |
| |
| assertTrue(result); |
| |
| ShadowHandler.runMainLooperOneTask(); |
| assertThat(task2.wasRun, equalTo(true)); |
| assertThat(task1.wasRun, equalTo(false)); |
| ShadowHandler.runMainLooperOneTask(); |
| assertThat(task1.wasRun, equalTo(true)); |
| } |
| |
| @Test |
| public void testSendMessageAtFrontOfQueueThenRunMainLooperOneMsgAtATime_shouldRunFrontOfQueueMsgFirst() throws Exception { |
| Handler handler = new Handler(); |
| |
| ShadowLooper.pauseMainLooper(); |
| // Post two messages to handler. Handle first message and confirm that msg posted |
| // to front is removed. |
| handler.obtainMessage(123).sendToTarget(); |
| Message frontMsg = handler.obtainMessage(345); |
| boolean result = handler.sendMessageAtFrontOfQueue(frontMsg); |
| |
| assertTrue(result); |
| |
| assertTrue(handler.hasMessages(123)); |
| assertTrue(handler.hasMessages(345)); |
| ShadowHandler.runMainLooperOneTask(); |
| assertTrue(handler.hasMessages(123)); |
| assertFalse(handler.hasMessages(345)); |
| ShadowHandler.runMainLooperOneTask(); |
| assertFalse(handler.hasMessages(123)); |
| assertFalse(handler.hasMessages(345)); |
| } |
| |
| @Test |
| public void sendEmptyMessage_addMessageToQueue() { |
| Robolectric.pauseMainLooper(); |
| Handler handler = new Handler(); |
| assertThat(handler.hasMessages(123), equalTo(false)); |
| handler.sendEmptyMessage(123); |
| assertThat(handler.hasMessages(456), equalTo(false)); |
| assertThat(handler.hasMessages(123), equalTo(true)); |
| Robolectric.idleMainLooper(0); |
| assertThat(handler.hasMessages(123), equalTo(false)); |
| } |
| |
| @Test |
| public void sendEmptyMessageDelayed_sendsMessageAtCorrectTime() { |
| Robolectric.pauseMainLooper(); |
| Handler handler = new Handler(); |
| handler.sendEmptyMessageDelayed(123, 500); |
| assertThat(handler.hasMessages(123), equalTo(true)); |
| Robolectric.idleMainLooper(100); |
| assertThat(handler.hasMessages(123), equalTo(true)); |
| Robolectric.idleMainLooper(400); |
| assertThat(handler.hasMessages(123), equalTo(false)); |
| } |
| |
| @Test |
| public void removeMessages_takesMessageOutOfQueue() { |
| Robolectric.pauseMainLooper(); |
| Handler handler = new Handler(); |
| handler.sendEmptyMessageDelayed(123, 500); |
| handler.removeMessages(123); |
| assertThat(handler.hasMessages(123), equalTo(false)); |
| } |
| |
| @Test |
| public void removeMessage_withSpecifiedObject() throws Exception { |
| Robolectric.pauseMainLooper(); |
| Handler handler = new Handler(); |
| Message.obtain(handler, 123, "foo").sendToTarget(); |
| Message.obtain(handler, 123, "bar").sendToTarget(); |
| |
| assertThat(handler.hasMessages(123), equalTo(true)); |
| assertThat(handler.hasMessages(123, "foo"), equalTo(true)); |
| assertThat(handler.hasMessages(123, "bar"), equalTo(true)); |
| assertThat(handler.hasMessages(123, "baz"), equalTo(false)); |
| |
| handler.removeMessages(123, "foo"); |
| assertThat(handler.hasMessages(123), equalTo(true)); |
| |
| handler.removeMessages(123, "bar"); |
| assertThat(handler.hasMessages(123), equalTo(false)); |
| } |
| |
| @Test |
| public void testHasMessagesWithWhatAndObject() { |
| Robolectric.pauseMainLooper(); |
| Object testObject = new Object(); |
| Handler handler = new Handler(); |
| Message message = handler.obtainMessage(123, testObject); |
| |
| assertFalse(handler.hasMessages(123, testObject)); |
| |
| handler.sendMessage(message); |
| |
| assertTrue(handler.hasMessages(123, testObject)); |
| } |
| |
| @Test |
| public void testSendToTarget() { |
| Robolectric.pauseMainLooper(); |
| Object testObject = new Object(); |
| Handler handler = new Handler(); |
| Message message = handler.obtainMessage(123, testObject); |
| |
| assertThat(handler, equalTo(message.getTarget())); |
| |
| message.sendToTarget(); |
| |
| assertTrue(handler.hasMessages(123, testObject)); |
| } |
| |
| @Test |
| public void removeMessages_removesFromLooperQueueAsWell() { |
| final boolean[] wasRun = new boolean[1]; |
| Robolectric.pauseMainLooper(); |
| Handler handler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| wasRun[0] = true; |
| } |
| }; |
| handler.sendEmptyMessageDelayed(123, 500); |
| handler.removeMessages(123); |
| Robolectric.unPauseMainLooper(); |
| assertThat(wasRun[0], equalTo(false)); |
| } |
| |
| @Test |
| public void shouldObtainMessage() throws Exception { |
| Message m0 = new Handler().obtainMessage(); |
| assertThat(m0.what, equalTo(0)); |
| assertThat(m0.obj, nullValue()); |
| |
| Message m1 = new Handler().obtainMessage(1); |
| assertThat(m1.what, equalTo(1)); |
| assertThat(m1.obj, nullValue()); |
| |
| Message m2 = new Handler().obtainMessage(1, "foo"); |
| assertThat(m2.what, equalTo(1)); |
| assertThat(m2.obj, equalTo((Object)"foo")); |
| |
| Message m3 = new Handler().obtainMessage(1, 2, 3); |
| assertThat(m3.what, equalTo(1)); |
| assertThat(m3.arg1, equalTo(2)); |
| assertThat(m3.arg2, equalTo(3)); |
| assertThat(m3.obj, nullValue()); |
| |
| Message m4 = new Handler().obtainMessage(1, 2, 3, "foo"); |
| assertThat(m4.what, equalTo(1)); |
| assertThat(m4.arg1, equalTo(2)); |
| assertThat(m4.arg2, equalTo(3)); |
| assertThat(m4.obj, equalTo((Object)"foo")); |
| } |
| |
| @Test |
| public void shouldSetWhenOnMessage() throws Exception { |
| final List<Message> msgs = new ArrayList<Message>(); |
| Handler h = new Handler(new Handler.Callback() { |
| @Override |
| public boolean handleMessage(Message msg) { |
| msgs.add(msg); |
| return false; |
| } |
| }); |
| |
| h.sendEmptyMessage(0); |
| h.sendEmptyMessageDelayed(0, 4000l); |
| Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable(); |
| h.sendEmptyMessageDelayed(0, 12000l); |
| Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable(); |
| assertThat(msgs.size(), equalTo(3)); |
| |
| Message m0 = msgs.get(0); |
| Message m1 = msgs.get(1); |
| Message m2 = msgs.get(2); |
| |
| assertThat(m0.getWhen(), equalTo(0l)); |
| assertThat(m1.getWhen(), equalTo(4000l)); |
| assertThat(m2.getWhen(), equalTo(16000l)); |
| } |
| |
| @Test |
| public void shouldRemoveMessageFromQueueBeforeDispatching() throws Exception { |
| Handler h = new Handler(Looper.myLooper()) { |
| @Override |
| public void handleMessage(Message msg) { |
| assertFalse(hasMessages(0)); |
| } |
| }; |
| h.sendEmptyMessage(0); |
| h.sendMessageAtFrontOfQueue(h.obtainMessage()); |
| } |
| |
| |
| private class Say implements Runnable { |
| private String event; |
| |
| public Say(String event) { |
| this.event = event; |
| } |
| |
| @Override |
| public void run() { |
| transcript.add(event); |
| } |
| } |
| } |