1package org.robolectric.shadows; 2 3import static org.assertj.core.api.Assertions.assertThat; 4import static org.assertj.core.api.Assertions.fail; 5import static org.junit.Assert.assertEquals; 6import static org.junit.Assert.assertFalse; 7import static org.junit.Assert.assertTrue; 8 9import android.os.AsyncTask; 10import java.util.ArrayList; 11import java.util.List; 12import java.util.concurrent.Executor; 13import java.util.concurrent.TimeUnit; 14import org.junit.Before; 15import org.junit.Test; 16import org.junit.runner.RunWith; 17import org.robolectric.Robolectric; 18import org.robolectric.RobolectricTestRunner; 19import org.robolectric.util.Join; 20 21@RunWith(RobolectricTestRunner.class) 22public class ShadowAsyncTaskTest { 23 private List<String> transcript; 24 25 @Before 26 public void setUp() throws Exception { 27 transcript = new ArrayList<>(); 28 Robolectric.getBackgroundThreadScheduler().pause(); 29 Robolectric.getForegroundThreadScheduler().pause(); 30 } 31 32 @Test 33 public void testNormalFlow() throws Exception { 34 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 35 36 asyncTask.execute("a", "b"); 37 assertThat(transcript).containsExactly("onPreExecute"); 38 transcript.clear(); 39 40 ShadowApplication.runBackgroundTasks(); 41 assertThat(transcript).containsExactly("doInBackground a, b"); 42 transcript.clear(); 43 assertEquals("Result should get stored in the AsyncTask", "c", asyncTask.get(100, TimeUnit.MILLISECONDS)); 44 45 ShadowLooper.runUiThreadTasks(); 46 assertThat(transcript).containsExactly("onPostExecute c"); 47 } 48 49 @Test 50 public void testCancelBeforeBackground() throws Exception { 51 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 52 53 asyncTask.execute("a", "b"); 54 assertThat(transcript).containsExactly("onPreExecute"); 55 transcript.clear(); 56 57 assertTrue(asyncTask.cancel(true)); 58 assertTrue(asyncTask.isCancelled()); 59 60 ShadowApplication.runBackgroundTasks(); 61 assertThat(transcript).isEmpty(); 62 63 ShadowLooper.runUiThreadTasks(); 64 assertThat(transcript).containsExactly("onCancelled"); 65 } 66 67 @Test 68 public void testCancelBeforePostExecute() throws Exception { 69 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 70 71 asyncTask.execute("a", "b"); 72 assertThat(transcript).containsExactly("onPreExecute"); 73 transcript.clear(); 74 75 ShadowApplication.runBackgroundTasks(); 76 assertThat(transcript).containsExactly("doInBackground a, b"); 77 transcript.clear(); 78 assertEquals("Result should get stored in the AsyncTask", "c", asyncTask.get(100, TimeUnit.MILLISECONDS)); 79 80 assertFalse(asyncTask.cancel(true)); 81 assertFalse(asyncTask.isCancelled()); 82 83 ShadowLooper.runUiThreadTasks(); 84 assertThat(transcript).containsExactly("onPostExecute c"); 85 } 86 87 @Test 88 public void progressUpdatesAreQueuedUntilBackgroundThreadFinishes() throws Exception { 89 AsyncTask<String, String, String> asyncTask = new MyAsyncTask() { 90 @Override 91 protected String doInBackground(String... strings) { 92 publishProgress("33%"); 93 publishProgress("66%"); 94 publishProgress("99%"); 95 return "done"; 96 } 97 }; 98 99 asyncTask.execute("a", "b"); 100 assertThat(transcript).containsExactly("onPreExecute"); 101 transcript.clear(); 102 103 ShadowApplication.runBackgroundTasks(); 104 assertThat(transcript).isEmpty(); 105 assertEquals("Result should get stored in the AsyncTask", "done", asyncTask.get(100, TimeUnit.MILLISECONDS)); 106 107 ShadowLooper.runUiThreadTasks(); 108 assertThat(transcript).containsExactly( 109 "onProgressUpdate 33%", 110 "onProgressUpdate 66%", 111 "onProgressUpdate 99%", 112 "onPostExecute done" 113 ); 114 } 115 116 @Test 117 public void executeReturnsAsyncTask() throws Exception { 118 Robolectric.getBackgroundThreadScheduler().unPause(); 119 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 120 assertThat(asyncTask.execute("a", "b").get()).isEqualTo("c"); 121 } 122 123 @Test 124 public void shouldGetStatusForAsyncTask() throws Exception { 125 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 126 assertThat(asyncTask.getStatus()).isEqualTo(AsyncTask.Status.PENDING); 127 asyncTask.execute("a"); 128 assertThat(asyncTask.getStatus()).isEqualTo(AsyncTask.Status.RUNNING); 129 Robolectric.getBackgroundThreadScheduler().unPause(); 130 assertThat(asyncTask.getStatus()).isEqualTo(AsyncTask.Status.FINISHED); 131 } 132 133 @Test 134 public void onPostExecute_doesNotSwallowExceptions() throws Exception { 135 Robolectric.getBackgroundThreadScheduler().unPause(); 136 Robolectric.getForegroundThreadScheduler().unPause(); 137 138 AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() { 139 @Override 140 protected Void doInBackground(Void... params) { 141 return null; 142 } 143 144 @Override 145 protected void onPostExecute(Void aVoid) { 146 throw new RuntimeException("Don't swallow me!"); 147 } 148 }; 149 150 try { 151 asyncTask.execute(); 152 fail("Task swallowed onPostExecute() exception!"); 153 } catch (RuntimeException e) { 154 assertThat(e.getCause().getMessage()).isEqualTo("Don't swallow me!"); 155 } 156 } 157 158 @Test 159 public void executeOnExecutor_usesPassedExecutor() throws Exception { 160 AsyncTask<String, String, String> asyncTask = new MyAsyncTask(); 161 162 assertThat(asyncTask.getStatus()).isEqualTo(AsyncTask.Status.PENDING); 163 164 asyncTask.executeOnExecutor(new ImmediateExecutor(), "a", "b"); 165 166 assertThat(asyncTask.getStatus()).isEqualTo(AsyncTask.Status.FINISHED); 167 assertThat(transcript).containsExactly("onPreExecute", "doInBackground a, b"); 168 transcript.clear(); 169 assertEquals("Result should get stored in the AsyncTask", "c", asyncTask.get()); 170 171 ShadowLooper.runUiThreadTasks(); 172 assertThat(transcript).containsExactly("onPostExecute c"); 173 } 174 175 private class MyAsyncTask extends AsyncTask<String, String, String> { 176 @Override 177 protected void onPreExecute() { 178 transcript.add("onPreExecute"); 179 } 180 181 @Override 182 protected String doInBackground(String... strings) { 183 transcript.add("doInBackground " + Join.join(", ", (Object[]) strings)); 184 return "c"; 185 } 186 187 @Override 188 protected void onProgressUpdate(String... values) { 189 transcript.add("onProgressUpdate " + Join.join(", ", (Object[]) values)); 190 } 191 192 @Override 193 protected void onPostExecute(String s) { 194 transcript.add("onPostExecute " + s); 195 } 196 197 @Override 198 protected void onCancelled() { 199 transcript.add("onCancelled"); 200 } 201 } 202 203 public static class ImmediateExecutor implements Executor { 204 @Override 205 public void execute(Runnable command) { 206 command.run(); 207 } 208 } 209} 210