xref: /aosp_15_r20/external/robolectric/robolectric/src/test/java/org/robolectric/shadows/ShadowTextViewTest.java (revision e6ba16074e6af37d123cb567d575f496bf0a58ee)
1 package org.robolectric.shadows;
2 
3 import static com.google.common.truth.Truth.assertThat;
4 import static java.util.Arrays.asList;
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.assertSame;
10 import static org.junit.Assert.assertTrue;
11 import static org.mockito.ArgumentMatchers.eq;
12 import static org.mockito.Mockito.mock;
13 import static org.mockito.Mockito.verify;
14 import static org.robolectric.Robolectric.buildActivity;
15 import static org.robolectric.Shadows.shadowOf;
16 
17 import android.app.Activity;
18 import android.graphics.Typeface;
19 import android.text.Editable;
20 import android.text.InputFilter;
21 import android.text.InputType;
22 import android.text.Selection;
23 import android.text.Spannable;
24 import android.text.SpannableStringBuilder;
25 import android.text.TextWatcher;
26 import android.text.method.ArrowKeyMovementMethod;
27 import android.text.method.MovementMethod;
28 import android.text.method.PasswordTransformationMethod;
29 import android.text.style.URLSpan;
30 import android.text.util.Linkify;
31 import android.util.TypedValue;
32 import android.view.Gravity;
33 import android.view.KeyEvent;
34 import android.view.MotionEvent;
35 import android.view.inputmethod.EditorInfo;
36 import android.widget.FrameLayout;
37 import android.widget.TextView;
38 import androidx.test.core.app.ApplicationProvider;
39 import androidx.test.ext.junit.runners.AndroidJUnit4;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Random;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.robolectric.R;
49 import org.robolectric.android.controller.ActivityController;
50 import org.robolectric.annotation.GraphicsMode;
51 import org.robolectric.annotation.GraphicsMode.Mode;
52 import org.robolectric.shadow.api.Shadow;
53 
54 @RunWith(AndroidJUnit4.class)
55 @GraphicsMode(Mode.LEGACY)
56 
57 public class ShadowTextViewTest {
58 
59   private static final String INITIAL_TEXT = "initial text";
60   private static final String NEW_TEXT = "new text";
61   private TextView textView;
62   private ActivityController<Activity> activityController;
63 
64   @Before
setUp()65   public void setUp() throws Exception {
66     activityController = buildActivity(Activity.class);
67     Activity activity = activityController.create().get();
68     textView = new TextView(activity);
69     activity.setContentView(textView);
70     activityController.start().resume().visible();
71   }
72 
73   @Test
shouldTriggerTheImeListener()74   public void shouldTriggerTheImeListener() {
75     TestOnEditorActionListener actionListener = new TestOnEditorActionListener();
76     textView.setOnEditorActionListener(actionListener);
77 
78     textView.onEditorAction(EditorInfo.IME_ACTION_GO);
79 
80     assertThat(actionListener.textView).isSameInstanceAs(textView);
81     assertThat(actionListener.sentImeId).isEqualTo(EditorInfo.IME_ACTION_GO);
82   }
83 
84   @Test
shouldCreateGetterForEditorActionListener()85   public void shouldCreateGetterForEditorActionListener() {
86     TestOnEditorActionListener actionListener = new TestOnEditorActionListener();
87 
88     textView.setOnEditorActionListener(actionListener);
89 
90     assertThat(shadowOf(textView).getOnEditorActionListener()).isSameInstanceAs(actionListener);
91   }
92 
93   @Test
testGetUrls()94   public void testGetUrls() {
95     Locale.setDefault(Locale.ENGLISH);
96     textView.setAutoLinkMask(Linkify.ALL);
97     textView.setText("here's some text http://google.com/\nblah\thttp://another.com/123?456 blah");
98 
99     assertThat(urlStringsFrom(textView.getUrls()))
100         .isEqualTo(asList("http://google.com", "http://another.com/123?456"));
101   }
102 
103   @Test
testGetGravity()104   public void testGetGravity() {
105     assertThat(textView.getGravity()).isNotEqualTo(Gravity.CENTER);
106     textView.setGravity(Gravity.CENTER);
107     assertThat(textView.getGravity()).isEqualTo(Gravity.CENTER);
108   }
109 
110   @Test
testMovementMethod()111   public void testMovementMethod() {
112     MovementMethod movement = new ArrowKeyMovementMethod();
113 
114     assertNull(textView.getMovementMethod());
115     textView.setMovementMethod(movement);
116     assertThat(textView.getMovementMethod()).isSameInstanceAs(movement);
117   }
118 
119   @Test
testLinksClickable()120   public void testLinksClickable() {
121     assertThat(textView.getLinksClickable()).isTrue();
122 
123     textView.setLinksClickable(false);
124     assertThat(textView.getLinksClickable()).isFalse();
125 
126     textView.setLinksClickable(true);
127     assertThat(textView.getLinksClickable()).isTrue();
128   }
129 
130   @Test
testGetTextAppearanceId()131   public void testGetTextAppearanceId() {
132     textView.setTextAppearance(
133         ApplicationProvider.getApplicationContext(), android.R.style.TextAppearance_Small);
134 
135     assertThat(shadowOf(textView).getTextAppearanceId())
136         .isEqualTo(android.R.style.TextAppearance_Small);
137   }
138 
139   @Test
shouldSetTextAndTextColorWhileInflatingXmlLayout()140   public void shouldSetTextAndTextColorWhileInflatingXmlLayout() {
141     Activity activity = activityController.get();
142     activity.setContentView(R.layout.text_views);
143 
144     TextView black = activity.findViewById(R.id.black_text_view);
145     assertThat(black.getText().toString()).isEqualTo("Black Text");
146     assertThat(black.getCurrentTextColor()).isEqualTo(0xff000000);
147 
148     TextView white = activity.findViewById(R.id.white_text_view);
149     assertThat(white.getText().toString()).isEqualTo("White Text");
150     assertThat(white.getCurrentTextColor())
151         .isEqualTo(activity.getResources().getColor(android.R.color.white));
152 
153     TextView grey = activity.findViewById(R.id.grey_text_view);
154     assertThat(grey.getText().toString()).isEqualTo("Grey Text");
155     assertThat(grey.getCurrentTextColor())
156         .isEqualTo(activity.getResources().getColor(R.color.grey42));
157   }
158 
159   @Test
shouldSetHintAndHintColorWhileInflatingXmlLayout()160   public void shouldSetHintAndHintColorWhileInflatingXmlLayout() {
161     Activity activity = activityController.get();
162     activity.setContentView(R.layout.text_views_hints);
163 
164     TextView black = activity.findViewById(R.id.black_text_view_hint);
165     assertThat(black.getHint().toString()).isEqualTo("Black Hint");
166     assertThat(black.getCurrentHintTextColor()).isEqualTo(0xff000000);
167 
168     TextView white = activity.findViewById(R.id.white_text_view_hint);
169     assertThat(white.getHint().toString()).isEqualTo("White Hint");
170     assertThat(white.getCurrentHintTextColor())
171         .isEqualTo(activity.getResources().getColor(android.R.color.white));
172 
173     TextView grey = activity.findViewById(R.id.grey_text_view_hint);
174     assertThat(grey.getHint().toString()).isEqualTo("Grey Hint");
175     assertThat(grey.getCurrentHintTextColor())
176         .isEqualTo(activity.getResources().getColor(R.color.grey42));
177   }
178 
179   @Test
shouldNotHaveTransformationMethodByDefault()180   public void shouldNotHaveTransformationMethodByDefault() {
181     assertThat(textView.getTransformationMethod()).isNull();
182   }
183 
184   @Test
shouldAllowSettingATransformationMethod()185   public void shouldAllowSettingATransformationMethod() {
186     textView.setTransformationMethod(PasswordTransformationMethod.getInstance());
187     assertThat(textView.getTransformationMethod()).isInstanceOf(PasswordTransformationMethod.class);
188   }
189 
190   @Test
testGetInputType()191   public void testGetInputType() {
192     assertThat(textView.getInputType())
193         .isNotEqualTo(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
194     textView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
195     assertThat(textView.getInputType())
196         .isEqualTo(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
197   }
198 
199   @Test
200   public void
givenATextViewWithATextWatcherAdded_WhenSettingTextWithTextResourceId_ShouldNotifyTextWatcher()201       givenATextViewWithATextWatcherAdded_WhenSettingTextWithTextResourceId_ShouldNotifyTextWatcher() {
202     MockTextWatcher mockTextWatcher = new MockTextWatcher();
203     textView.addTextChangedListener(mockTextWatcher);
204 
205     textView.setText(R.string.hello);
206 
207     assertEachTextWatcherEventWasInvoked(mockTextWatcher);
208   }
209 
210   @Test
211   public void
givenATextViewWithATextWatcherAdded_WhenSettingTextWithCharSequence_ShouldNotifyTextWatcher()212       givenATextViewWithATextWatcherAdded_WhenSettingTextWithCharSequence_ShouldNotifyTextWatcher() {
213     MockTextWatcher mockTextWatcher = new MockTextWatcher();
214     textView.addTextChangedListener(mockTextWatcher);
215 
216     textView.setText("text");
217 
218     assertEachTextWatcherEventWasInvoked(mockTextWatcher);
219   }
220 
221   @Test
givenATextViewWithATextWatcherAdded_WhenSettingNullText_ShouldNotifyTextWatcher()222   public void givenATextViewWithATextWatcherAdded_WhenSettingNullText_ShouldNotifyTextWatcher() {
223     MockTextWatcher mockTextWatcher = new MockTextWatcher();
224     textView.addTextChangedListener(mockTextWatcher);
225 
226     textView.setText(null);
227 
228     assertEachTextWatcherEventWasInvoked(mockTextWatcher);
229   }
230 
231   @Test
232   public void
givenATextViewWithMultipleTextWatchersAdded_WhenSettingText_ShouldNotifyEachTextWatcher()233       givenATextViewWithMultipleTextWatchersAdded_WhenSettingText_ShouldNotifyEachTextWatcher() {
234     List<MockTextWatcher> mockTextWatchers = anyNumberOfTextWatchers();
235     for (MockTextWatcher textWatcher : mockTextWatchers) {
236       textView.addTextChangedListener(textWatcher);
237     }
238 
239     textView.setText("text");
240 
241     for (MockTextWatcher textWatcher : mockTextWatchers) {
242       assertEachTextWatcherEventWasInvoked(textWatcher);
243     }
244   }
245 
246   @Test
whenSettingText_ShouldFireBeforeTextChangedWithCorrectArguments()247   public void whenSettingText_ShouldFireBeforeTextChangedWithCorrectArguments() {
248     textView.setText(INITIAL_TEXT);
249     TextWatcher mockTextWatcher = mock(TextWatcher.class);
250     textView.addTextChangedListener(mockTextWatcher);
251 
252     textView.setText(NEW_TEXT);
253 
254     verify(mockTextWatcher)
255         .beforeTextChanged(INITIAL_TEXT, 0, INITIAL_TEXT.length(), NEW_TEXT.length());
256   }
257 
258   @Test
whenSettingText_ShouldFireOnTextChangedWithCorrectArguments()259   public void whenSettingText_ShouldFireOnTextChangedWithCorrectArguments() {
260     textView.setText(INITIAL_TEXT);
261     TextWatcher mockTextWatcher = mock(TextWatcher.class);
262     textView.addTextChangedListener(mockTextWatcher);
263 
264     textView.setText(NEW_TEXT);
265 
266     ArgumentCaptor<SpannableStringBuilder> builderCaptor =
267         ArgumentCaptor.forClass(SpannableStringBuilder.class);
268     verify(mockTextWatcher)
269         .onTextChanged(
270             builderCaptor.capture(), eq(0), eq(INITIAL_TEXT.length()), eq(NEW_TEXT.length()));
271     assertThat(builderCaptor.getValue().toString()).isEqualTo(NEW_TEXT);
272   }
273 
274   @Test
whenSettingText_ShouldFireAfterTextChangedWithCorrectArgument()275   public void whenSettingText_ShouldFireAfterTextChangedWithCorrectArgument() {
276     MockTextWatcher mockTextWatcher = new MockTextWatcher();
277     textView.addTextChangedListener(mockTextWatcher);
278 
279     textView.setText(NEW_TEXT);
280 
281     assertThat(mockTextWatcher.afterTextChangeArgument.toString()).isEqualTo(NEW_TEXT);
282   }
283 
284   @Test
whenAppendingText_ShouldAppendNewTextAfterOldOne()285   public void whenAppendingText_ShouldAppendNewTextAfterOldOne() {
286     textView.setText(INITIAL_TEXT);
287     textView.append(NEW_TEXT);
288 
289     assertThat(textView.getText().toString()).isEqualTo(INITIAL_TEXT + NEW_TEXT);
290   }
291 
292   @Test
whenAppendingText_ShouldFireBeforeTextChangedWithCorrectArguments()293   public void whenAppendingText_ShouldFireBeforeTextChangedWithCorrectArguments() {
294     textView.setText(INITIAL_TEXT);
295     TextWatcher mockTextWatcher = mock(TextWatcher.class);
296     textView.addTextChangedListener(mockTextWatcher);
297 
298     textView.append(NEW_TEXT);
299 
300     verify(mockTextWatcher)
301         .beforeTextChanged(
302             eq(INITIAL_TEXT), eq(0), eq(INITIAL_TEXT.length()), eq(INITIAL_TEXT.length()));
303   }
304 
305   @Test
whenAppendingText_ShouldFireOnTextChangedWithCorrectArguments()306   public void whenAppendingText_ShouldFireOnTextChangedWithCorrectArguments() {
307     textView.setText(INITIAL_TEXT);
308     TextWatcher mockTextWatcher = mock(TextWatcher.class);
309     textView.addTextChangedListener(mockTextWatcher);
310 
311     textView.append(NEW_TEXT);
312 
313     ArgumentCaptor<SpannableStringBuilder> builderCaptor =
314         ArgumentCaptor.forClass(SpannableStringBuilder.class);
315     verify(mockTextWatcher)
316         .onTextChanged(
317             builderCaptor.capture(), eq(0), eq(INITIAL_TEXT.length()), eq(INITIAL_TEXT.length()));
318     assertThat(builderCaptor.getValue().toString()).isEqualTo(INITIAL_TEXT + NEW_TEXT);
319   }
320 
321   @Test
whenAppendingText_ShouldFireAfterTextChangedWithCorrectArgument()322   public void whenAppendingText_ShouldFireAfterTextChangedWithCorrectArgument() {
323     textView.setText(INITIAL_TEXT);
324     MockTextWatcher mockTextWatcher = new MockTextWatcher();
325     textView.addTextChangedListener(mockTextWatcher);
326 
327     textView.append(NEW_TEXT);
328 
329     assertThat(mockTextWatcher.afterTextChangeArgument.toString())
330         .isEqualTo(INITIAL_TEXT + NEW_TEXT);
331   }
332 
333   @Test
removeTextChangedListener_shouldRemoveTheListener()334   public void removeTextChangedListener_shouldRemoveTheListener() {
335     MockTextWatcher watcher = new MockTextWatcher();
336     textView.addTextChangedListener(watcher);
337     assertTrue(shadowOf(textView).getWatchers().contains(watcher));
338 
339     textView.removeTextChangedListener(watcher);
340     assertFalse(shadowOf(textView).getWatchers().contains(watcher));
341   }
342 
343   @Test
getPaint_returnsMeasureTextEnabledObject()344   public void getPaint_returnsMeasureTextEnabledObject() {
345     assertThat(textView.getPaint().measureText("12345")).isEqualTo(5f);
346   }
347 
348   @Test
append_whenSelectionIsAtTheEnd_shouldKeepSelectionAtTheEnd()349   public void append_whenSelectionIsAtTheEnd_shouldKeepSelectionAtTheEnd() {
350     textView.setText("1", TextView.BufferType.EDITABLE);
351     Selection.setSelection(textView.getEditableText(), 0, 0);
352     textView.append("2");
353     assertEquals(0, textView.getSelectionEnd());
354     assertEquals(0, textView.getSelectionStart());
355 
356     Selection.setSelection(textView.getEditableText(), 2, 2);
357     textView.append("3");
358     assertEquals(3, textView.getSelectionEnd());
359     assertEquals(3, textView.getSelectionStart());
360   }
361 
362   @Test
append_whenSelectionReachesToEnd_shouldExtendSelectionToTheEnd()363   public void append_whenSelectionReachesToEnd_shouldExtendSelectionToTheEnd() {
364     textView.setText("12", TextView.BufferType.EDITABLE);
365     Selection.setSelection(textView.getEditableText(), 0, 2);
366     textView.append("3");
367     assertEquals(3, textView.getSelectionEnd());
368     assertEquals(0, textView.getSelectionStart());
369   }
370 
371   @Test
372   public void
testSetCompountDrawablesWithIntrinsicBounds_int_shouldCreateDrawablesWithResourceIds()373       testSetCompountDrawablesWithIntrinsicBounds_int_shouldCreateDrawablesWithResourceIds() {
374     textView.setCompoundDrawablesWithIntrinsicBounds(
375         R.drawable.an_image,
376         R.drawable.an_other_image,
377         R.drawable.third_image,
378         R.drawable.fourth_image);
379 
380     assertEquals(
381         R.drawable.an_image, shadowOf(textView.getCompoundDrawables()[0]).getCreatedFromResId());
382     assertEquals(
383         R.drawable.an_other_image,
384         shadowOf(textView.getCompoundDrawables()[1]).getCreatedFromResId());
385     assertEquals(
386         R.drawable.third_image, shadowOf(textView.getCompoundDrawables()[2]).getCreatedFromResId());
387     assertEquals(
388         R.drawable.fourth_image,
389         shadowOf(textView.getCompoundDrawables()[3]).getCreatedFromResId());
390   }
391 
392   @Test
testSetCompountDrawablesWithIntrinsicBounds_int_shouldNotCreateDrawablesForZero()393   public void testSetCompountDrawablesWithIntrinsicBounds_int_shouldNotCreateDrawablesForZero() {
394     textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
395 
396     assertNull(textView.getCompoundDrawables()[0]);
397     assertNull(textView.getCompoundDrawables()[1]);
398     assertNull(textView.getCompoundDrawables()[2]);
399     assertNull(textView.getCompoundDrawables()[3]);
400   }
401 
402   @Test
canSetAndGetTypeface()403   public void canSetAndGetTypeface() {
404     Typeface typeface = Shadow.newInstanceOf(Typeface.class);
405     textView.setTypeface(typeface);
406     assertSame(typeface, textView.getTypeface());
407   }
408 
409   @Test
onTouchEvent_shouldCallMovementMethodOnTouchEventWithSetMotionEvent()410   public void onTouchEvent_shouldCallMovementMethodOnTouchEventWithSetMotionEvent() {
411     TestMovementMethod testMovementMethod = new TestMovementMethod();
412     textView.setMovementMethod(testMovementMethod);
413     textView.setLayoutParams(new FrameLayout.LayoutParams(100, 100));
414     textView.measure(100, 100);
415 
416     MotionEvent event = MotionEvent.obtain(0, 0, 0, 0, 0, 0);
417     textView.dispatchTouchEvent(event);
418 
419     assertEquals(testMovementMethod.event, event);
420   }
421 
422   @Test
testGetError()423   public void testGetError() {
424     assertNull(textView.getError());
425     CharSequence error = "myError";
426     textView.setError(error);
427     assertEquals(error.toString(), textView.getError().toString());
428   }
429 
430   @Test
canSetAndGetInputFilters()431   public void canSetAndGetInputFilters() {
432     final InputFilter[] expectedFilters = new InputFilter[] {new InputFilter.LengthFilter(1)};
433     textView.setFilters(expectedFilters);
434     assertThat(textView.getFilters()).isSameInstanceAs(expectedFilters);
435   }
436 
437   @Test
testHasSelectionReturnsTrue()438   public void testHasSelectionReturnsTrue() {
439     textView.setText("1", TextView.BufferType.SPANNABLE);
440     textView.onTextContextMenuItem(android.R.id.selectAll);
441     assertTrue(textView.hasSelection());
442   }
443 
444   @Test
testHasSelectionReturnsFalse()445   public void testHasSelectionReturnsFalse() {
446     textView.setText("1", TextView.BufferType.SPANNABLE);
447     assertFalse(textView.hasSelection());
448   }
449 
450   @Test
whenSettingTextToNull_WatchersSeeEmptyString()451   public void whenSettingTextToNull_WatchersSeeEmptyString() {
452     TextWatcher mockTextWatcher = mock(TextWatcher.class);
453     textView.addTextChangedListener(mockTextWatcher);
454 
455     textView.setText(null);
456 
457     ArgumentCaptor<SpannableStringBuilder> builderCaptor =
458         ArgumentCaptor.forClass(SpannableStringBuilder.class);
459     verify(mockTextWatcher).onTextChanged(builderCaptor.capture(), eq(0), eq(0), eq(0));
460     assertThat(builderCaptor.getValue().toString()).isEmpty();
461   }
462 
463   @Test
getPaint_returnsNonNull()464   public void getPaint_returnsNonNull() {
465     assertNotNull(textView.getPaint());
466   }
467 
468   @Test
testNoArgAppend()469   public void testNoArgAppend() {
470     textView.setText("a");
471     textView.append("b");
472     assertThat(textView.getText().toString()).isEqualTo("ab");
473   }
474 
475   @Test
setTextSize_shouldHandleDips()476   public void setTextSize_shouldHandleDips() {
477     textView.getContext().getResources().getDisplayMetrics().density = 1.5f;
478     textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
479     assertThat(textView.getTextSize()).isEqualTo(15f);
480     textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
481     assertThat(textView.getTextSize()).isEqualTo(30f);
482   }
483 
484   @Test
setTextSize_shouldHandleSp()485   public void setTextSize_shouldHandleSp() {
486     textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
487     assertThat(textView.getTextSize()).isEqualTo(10f);
488 
489     textView.getContext().getResources().getDisplayMetrics().scaledDensity = 1.5f;
490 
491     textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
492     assertThat(textView.getTextSize()).isEqualTo(15f);
493   }
494 
495   @Test
setTextSize_shouldHandlePixels()496   public void setTextSize_shouldHandlePixels() {
497     textView.getContext().getResources().getDisplayMetrics().density = 1.5f;
498     textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 10);
499     assertThat(textView.getTextSize()).isEqualTo(10f);
500     textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 20);
501     assertThat(textView.getTextSize()).isEqualTo(20f);
502   }
503 
504   @Test
getPaintFlagsAndSetPaintFlags_shouldWork()505   public void getPaintFlagsAndSetPaintFlags_shouldWork() {
506     textView.setPaintFlags(100);
507     assertThat(textView.getPaintFlags()).isEqualTo(100);
508   }
509 
510   @Test
setCompoundDrawablesWithIntrinsicBounds_setsValues()511   public void setCompoundDrawablesWithIntrinsicBounds_setsValues() {
512     textView.setCompoundDrawablesWithIntrinsicBounds(
513         R.drawable.l0_red, R.drawable.l1_orange, R.drawable.l2_yellow, R.drawable.l3_green);
514     assertThat(shadowOf(textView).getCompoundDrawablesWithIntrinsicBoundsLeft())
515         .isEqualTo(R.drawable.l0_red);
516     assertThat(shadowOf(textView).getCompoundDrawablesWithIntrinsicBoundsTop())
517         .isEqualTo(R.drawable.l1_orange);
518     assertThat(shadowOf(textView).getCompoundDrawablesWithIntrinsicBoundsRight())
519         .isEqualTo(R.drawable.l2_yellow);
520     assertThat(shadowOf(textView).getCompoundDrawablesWithIntrinsicBoundsBottom())
521         .isEqualTo(R.drawable.l3_green);
522   }
523 
anyNumberOfTextWatchers()524   private List<MockTextWatcher> anyNumberOfTextWatchers() {
525     List<MockTextWatcher> mockTextWatchers = new ArrayList<>();
526     int numberBetweenOneAndTen = new Random().nextInt(10) + 1;
527     for (int i = 0; i < numberBetweenOneAndTen; i++) {
528       mockTextWatchers.add(new MockTextWatcher());
529     }
530     return mockTextWatchers;
531   }
532 
assertEachTextWatcherEventWasInvoked(MockTextWatcher mockTextWatcher)533   private void assertEachTextWatcherEventWasInvoked(MockTextWatcher mockTextWatcher) {
534     assertTrue(
535         "Expected each TextWatcher event to" + " have" + " been" + " invoked" + " once",
536         mockTextWatcher.methodsCalled.size() == 3);
537 
538     assertThat(mockTextWatcher.methodsCalled.get(0)).isEqualTo("beforeTextChanged");
539     assertThat(mockTextWatcher.methodsCalled.get(1)).isEqualTo("onTextChanged");
540     assertThat(mockTextWatcher.methodsCalled.get(2)).isEqualTo("afterTextChanged");
541   }
542 
urlStringsFrom(URLSpan[] urlSpans)543   private List<String> urlStringsFrom(URLSpan[] urlSpans) {
544     List<String> urls = new ArrayList<>();
545     for (URLSpan urlSpan : urlSpans) {
546       urls.add(urlSpan.getURL());
547     }
548     return urls;
549   }
550 
551   private static class TestOnEditorActionListener implements TextView.OnEditorActionListener {
552     private TextView textView;
553     private int sentImeId;
554 
555     @Override
onEditorAction(TextView textView, int sentImeId, KeyEvent keyEvent)556     public boolean onEditorAction(TextView textView, int sentImeId, KeyEvent keyEvent) {
557       this.textView = textView;
558       this.sentImeId = sentImeId;
559       return false;
560     }
561   }
562 
563   private static class MockTextWatcher implements TextWatcher {
564 
565     List<String> methodsCalled = new ArrayList<>();
566     Editable afterTextChangeArgument;
567 
568     @Override
beforeTextChanged(CharSequence s, int start, int count, int after)569     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
570       methodsCalled.add("beforeTextChanged");
571     }
572 
573     @Override
onTextChanged(CharSequence s, int start, int before, int count)574     public void onTextChanged(CharSequence s, int start, int before, int count) {
575       methodsCalled.add("onTextChanged");
576     }
577 
578     @Override
afterTextChanged(Editable s)579     public void afterTextChanged(Editable s) {
580       methodsCalled.add("afterTextChanged");
581       afterTextChangeArgument = s;
582     }
583   }
584 
585   private static class TestMovementMethod implements MovementMethod {
586     public MotionEvent event;
587 
588     @Override
initialize(TextView widget, Spannable text)589     public void initialize(TextView widget, Spannable text) {}
590 
591     @Override
onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event)592     public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event) {
593       return false;
594     }
595 
596     @Override
onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event)597     public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event) {
598       return false;
599     }
600 
601     @Override
onKeyOther(TextView view, Spannable text, KeyEvent event)602     public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
603       return false;
604     }
605 
606     @Override
onTakeFocus(TextView widget, Spannable text, int direction)607     public void onTakeFocus(TextView widget, Spannable text, int direction) {}
608 
609     @Override
onTrackballEvent(TextView widget, Spannable text, MotionEvent event)610     public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
611       return false;
612     }
613 
614     @Override
onTouchEvent(TextView widget, Spannable text, MotionEvent event)615     public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) {
616       this.event = event;
617       return false;
618     }
619 
620     @Override
canSelectArbitrarily()621     public boolean canSelectArbitrarily() {
622       return false;
623     }
624 
625     @Override
onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event)626     public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) {
627       return false;
628     }
629   }
630 }
631