1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.LOLLIPOP;
4 import static com.google.common.truth.Truth.assertThat;
5 import static org.junit.Assert.assertEquals;
6 import static org.junit.Assert.assertFalse;
7 import static org.junit.Assert.assertNotNull;
8 import static org.junit.Assert.assertNull;
9 import static org.junit.Assert.assertTrue;
10 import static org.robolectric.RuntimeEnvironment.application;
11 import static org.robolectric.Shadows.shadowOf;
12 
13 import android.app.Activity;
14 import android.app.AlertDialog;
15 import android.app.Application;
16 import android.app.Dialog;
17 import android.content.ContextWrapper;
18 import android.content.DialogInterface;
19 import android.view.View;
20 import android.widget.ArrayAdapter;
21 import android.widget.EditText;
22 import androidx.test.core.app.ApplicationProvider;
23 import androidx.test.ext.junit.runners.AndroidJUnit4;
24 import java.util.ArrayList;
25 import java.util.List;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.robolectric.R;
30 import org.robolectric.Robolectric;
31 import org.robolectric.android.CustomView;
32 import org.robolectric.annotation.Config;
33 
34 @RunWith(AndroidJUnit4.class)
35 public class ShadowAlertDialogTest {
36 
37   private Application context;
38 
39   @Before
setUp()40   public void setUp() throws Exception {
41     context = ApplicationProvider.getApplicationContext();
42   }
43 
44   @Test
testBuilder()45   public void testBuilder() throws Exception {
46     AlertDialog.Builder builder = new AlertDialog.Builder(application);
47     builder.setTitle("title").setMessage("message");
48     builder.setCancelable(true);
49     AlertDialog alert = builder.create();
50     alert.show();
51 
52     assertThat(alert.isShowing()).isTrue();
53 
54     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
55     assertEquals("title", shadowAlertDialog.getTitle());
56     assertThat(shadowAlertDialog.getMessage()).isEqualTo("message");
57     assertThat(shadowAlertDialog.isCancelable()).isTrue();
58     assertThat(shadowOf(ShadowAlertDialog.getLatestAlertDialog())).isSameAs(shadowAlertDialog);
59     assertThat(ShadowAlertDialog.getLatestAlertDialog()).isSameAs(alert);
60   }
61 
62   @Test
nullTitleAndMessageAreOkay()63   public void nullTitleAndMessageAreOkay() throws Exception {
64     AlertDialog.Builder builder = new AlertDialog.Builder(application) //
65         .setTitle(null) //
66         .setMessage(null);
67     ShadowAlertDialog shadowAlertDialog = shadowOf(builder.create());
68     assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo("");
69     assertThat(shadowAlertDialog.getMessage()).isEqualTo("");
70   }
71 
72   @Test
getLatestAlertDialog_shouldReturnARealAlertDialog()73   public void getLatestAlertDialog_shouldReturnARealAlertDialog() throws Exception {
74     assertThat(ShadowAlertDialog.getLatestAlertDialog()).isNull();
75 
76     AlertDialog dialog = new AlertDialog.Builder(application).show();
77     assertThat(ShadowAlertDialog.getLatestAlertDialog()).isSameAs(dialog);
78   }
79 
80   @Test
shouldOnlyCreateRequestedButtons()81   public void shouldOnlyCreateRequestedButtons() throws Exception {
82     AlertDialog.Builder builder = new AlertDialog.Builder(application);
83     builder.setPositiveButton("OK", null);
84     AlertDialog dialog = builder.create();
85     dialog.show();
86     assertThat(dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility())
87         .isEqualTo(View.VISIBLE);
88     assertThat(dialog.getButton(AlertDialog.BUTTON_NEGATIVE).getVisibility()).isEqualTo(View.GONE);
89   }
90 
91   @Test
shouldAllowNullButtonListeners()92   public void shouldAllowNullButtonListeners() throws Exception {
93     AlertDialog.Builder builder = new AlertDialog.Builder(application);
94     builder.setPositiveButton("OK", null);
95     AlertDialog dialog = builder.create();
96     dialog.show();
97     ShadowView.clickOn(dialog.getButton(AlertDialog.BUTTON_POSITIVE));
98   }
99 
100   @Test
testSetMessageAfterCreation()101   public void testSetMessageAfterCreation() {
102     AlertDialog.Builder builder = new AlertDialog.Builder(application);
103     builder.setTitle("title").setMessage("message");
104     AlertDialog alert = builder.create();
105 
106     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
107     assertThat(shadowAlertDialog.getMessage()).isEqualTo("message");
108 
109     alert.setMessage("new message");
110     assertThat(shadowAlertDialog.getMessage()).isEqualTo("new message");
111 
112     alert.setMessage(null);
113     assertThat(shadowAlertDialog.getMessage()).isEqualTo("");
114   }
115 
116   @Test
shouldSetMessageFromResourceId()117   public void shouldSetMessageFromResourceId() throws Exception {
118     AlertDialog.Builder builder = new AlertDialog.Builder(application);
119     builder.setTitle("title").setMessage(R.string.hello);
120 
121     AlertDialog alert = builder.create();
122     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
123     assertThat(shadowAlertDialog.getMessage()).isEqualTo("Hello");
124   }
125 
126   @Test
shouldSetView()127   public void shouldSetView() throws Exception {
128     AlertDialog.Builder builder = new AlertDialog.Builder(application);
129     EditText view = new EditText(application);
130     builder.setView(view);
131 
132     AlertDialog alert = builder.create();
133     assertThat(shadowOf(alert).getView()).isEqualTo(view);
134   }
135 
136   @Test
137   @Config(minSdk = LOLLIPOP)
shouldSetView_withLayoutId()138   public void shouldSetView_withLayoutId() throws Exception {
139     AlertDialog.Builder builder = new AlertDialog.Builder(application);
140     builder.setView(R.layout.custom_layout);
141 
142     AlertDialog alert = builder.create();
143     View view = shadowOf(alert).getView();
144     assertThat(view.getClass()).isEqualTo(CustomView.class);
145   }
146 
147   @Test
shouldSetCustomTitleView()148   public void shouldSetCustomTitleView() throws Exception {
149     AlertDialog.Builder builder = new AlertDialog.Builder(application);
150     View view = new View(application);
151     assertThat(builder.setCustomTitle(view)).isSameAs(builder);
152 
153     AlertDialog alert = builder.create();
154     assertThat(shadowOf(alert).getCustomTitleView()).isEqualTo(view);
155   }
156 
157   @Test
clickingPositiveButtonDismissesDialog()158   public void clickingPositiveButtonDismissesDialog() throws Exception {
159     AlertDialog alertDialog = new AlertDialog.Builder(application)
160         .setPositiveButton("Positive", null).create();
161     alertDialog.show();
162 
163     assertTrue(alertDialog.isShowing());
164     alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
165     assertFalse(alertDialog.isShowing());
166   }
167 
168   @Test
clickingNeutralButtonDismissesDialog()169   public void clickingNeutralButtonDismissesDialog() throws Exception {
170     AlertDialog alertDialog = new AlertDialog.Builder(application)
171         .setNeutralButton("Neutral", new DialogInterface.OnClickListener() {
172           @Override
173           public void onClick(DialogInterface dialog, int which) {
174           }
175         }).create();
176     alertDialog.show();
177 
178     assertTrue(alertDialog.isShowing());
179     alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).performClick();
180     assertFalse(alertDialog.isShowing());
181   }
182 
183   @Test
clickingNegativeButtonDismissesDialog()184   public void clickingNegativeButtonDismissesDialog() throws Exception {
185     AlertDialog alertDialog = new AlertDialog.Builder(application)
186         .setNegativeButton("Negative", new DialogInterface.OnClickListener() {
187           @Override
188           public void onClick(DialogInterface dialog, int which) {
189           }
190         }).create();
191     alertDialog.show();
192 
193     assertTrue(alertDialog.isShowing());
194     alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).performClick();
195     assertFalse(alertDialog.isShowing());
196   }
197 
198   @Test
testBuilderWithItemArrayViaResourceId()199   public void testBuilderWithItemArrayViaResourceId() throws Exception {
200     AlertDialog.Builder builder = new AlertDialog.Builder(new ContextWrapper(context));
201 
202     builder.setTitle("title");
203     builder.setItems(R.array.alertDialogTestItems, new TestDialogOnClickListener());
204     AlertDialog alert = builder.create();
205     alert.show();
206 
207     assertThat(alert.isShowing()).isTrue();
208 
209     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
210     assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo("title");
211     assertThat(shadowAlertDialog.getItems().length).isEqualTo(2);
212     assertThat(shadowAlertDialog.getItems()[0]).isEqualTo("Aloha");
213     assertThat(shadowOf(ShadowAlertDialog.getLatestAlertDialog())).isSameAs(shadowAlertDialog);
214     assertThat(ShadowAlertDialog.getLatestAlertDialog()).isSameAs(alert);
215   }
216 
217   @Test
testBuilderWithAdapter()218   public void testBuilderWithAdapter() throws Exception {
219     List<Integer> list = new ArrayList<>();
220     list.add(99);
221     list.add(88);
222     list.add(77);
223     ArrayAdapter<Integer> adapter = new ArrayAdapter<>(context, R.layout.main, R.id.title, list);
224 
225     AlertDialog.Builder builder = new AlertDialog.Builder(application);
226     builder.setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() {
227       @Override
228       public void onClick(DialogInterface dialog, int item) {
229         dialog.dismiss();
230       }
231     });
232     AlertDialog alert = builder.create();
233     alert.show();
234 
235     assertTrue(alert.isShowing());
236     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
237     assertThat(shadowAlertDialog.getAdapter().getCount()).isEqualTo(3);
238     assertThat(shadowAlertDialog.getAdapter().getItem(0)).isEqualTo(99);
239   }
240 
241   @Test
show_setsLatestAlertDialogAndLatestDialog()242   public void show_setsLatestAlertDialogAndLatestDialog() {
243     AlertDialog alertDialog = new AlertDialog.Builder(context).create();
244     assertNull(ShadowDialog.getLatestDialog());
245     assertNull(ShadowAlertDialog.getLatestAlertDialog());
246 
247     alertDialog.show();
248 
249     assertEquals(alertDialog, ShadowDialog.getLatestDialog());
250     assertEquals(alertDialog, ShadowAlertDialog.getLatestAlertDialog());
251   }
252 
253   @Test
shouldCallTheClickListenerOfTheCheckedAdapterInASingleChoiceDialog()254   public void shouldCallTheClickListenerOfTheCheckedAdapterInASingleChoiceDialog()
255       throws Exception {
256     AlertDialog.Builder builder = new AlertDialog.Builder(new ContextWrapper(context));
257 
258     TestDialogOnClickListener listener = new TestDialogOnClickListener();
259     List<Integer> list = new ArrayList<>();
260     list.add(1);
261     list.add(2);
262     list.add(3);
263     ArrayAdapter<Integer> arrayAdapter =
264         new ArrayAdapter<>(context, R.layout.main, R.id.title, list);
265     builder.setSingleChoiceItems(arrayAdapter, 1, listener);
266 
267     AlertDialog alert = builder.create();
268     alert.show();
269 
270     ShadowAlertDialog shadowAlertDialog = shadowOf(alert);
271     shadowAlertDialog.clickOnItem(0);
272     assertThat(listener.transcript).containsExactly("clicked on 0");
273     listener.transcript.clear();
274 
275     shadowAlertDialog.clickOnItem(1);
276     assertThat(listener.transcript).containsExactly("clicked on 1");
277 
278   }
279 
280   @Test
shouldDelegateToDialogFindViewByIdIfViewIsNull()281   public void shouldDelegateToDialogFindViewByIdIfViewIsNull() {
282     AlertDialog dialog = new AlertDialog(context) {};
283 
284     assertThat((View) dialog.findViewById(99)).isNull();
285 
286     dialog.setContentView(R.layout.main);
287     assertNotNull(dialog.findViewById(R.id.title));
288   }
289 
290   @Test
shouldNotExplodeWhenNestingAlerts()291   public void shouldNotExplodeWhenNestingAlerts() throws Exception {
292     final Activity activity = Robolectric.buildActivity(Activity.class).create().get();
293     final AlertDialog nestedDialog = new AlertDialog.Builder(activity)
294         .setTitle("Dialog 2")
295         .setMessage("Another dialog")
296         .setPositiveButton("OK", null)
297         .create();
298 
299     final AlertDialog dialog = new AlertDialog.Builder(activity)
300         .setTitle("Dialog 1")
301         .setMessage("A dialog")
302         .setPositiveButton("Button 1", new DialogInterface.OnClickListener() {
303           @Override
304           public void onClick(DialogInterface dialog, int which) {
305             nestedDialog.show();
306           }
307         }).create();
308 
309     dialog.show();
310     assertThat(ShadowDialog.getLatestDialog()).isEqualTo(dialog);
311 
312     dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
313     assertThat(ShadowDialog.getLatestDialog()).isEqualTo(nestedDialog);
314   }
315 
316   @Test
alertControllerShouldStoreCorrectIconIdFromBuilder()317   public void alertControllerShouldStoreCorrectIconIdFromBuilder() {
318     AlertDialog.Builder builder = new AlertDialog.Builder(application);
319     builder.setIcon(R.drawable.an_image);
320 
321     AlertDialog alertDialog = builder.create();
322     assertThat(shadowOf(alertDialog).getIconId()).isEqualTo(R.drawable.an_image);
323   }
324 
325   private static class TestDialogOnClickListener implements DialogInterface.OnClickListener {
326 
327     private final ArrayList<String> transcript = new ArrayList<>();
328 
329     @Override
onClick(DialogInterface dialog, int item)330     public void onClick(DialogInterface dialog, int item) {
331       transcript.add("clicked on " + item);
332     }
333   }
334 }
335