Home | History | Annotate | Download | only in shadows
      1 package com.xtremelabs.robolectric.shadows;
      2 
      3 import android.app.Activity;
      4 import android.graphics.Typeface;
      5 import android.text.*;
      6 import android.text.method.ArrowKeyMovementMethod;
      7 import android.text.method.MovementMethod;
      8 import android.text.style.URLSpan;
      9 import android.view.Gravity;
     10 import android.view.KeyEvent;
     11 import android.view.MotionEvent;
     12 import android.view.inputmethod.EditorInfo;
     13 import android.widget.TextView;
     14 import com.xtremelabs.robolectric.R;
     15 import com.xtremelabs.robolectric.Robolectric;
     16 import com.xtremelabs.robolectric.WithTestDefaultsRunner;
     17 import junit.framework.Assert;
     18 import org.hamcrest.CoreMatchers;
     19 import org.junit.Before;
     20 import org.junit.Test;
     21 import org.junit.runner.RunWith;
     22 
     23 import java.util.ArrayList;
     24 import java.util.List;
     25 import java.util.Random;
     26 
     27 import static com.xtremelabs.robolectric.Robolectric.shadowOf;
     28 import static java.util.Arrays.asList;
     29 import static junit.framework.Assert.assertFalse;
     30 import static org.hamcrest.CoreMatchers.*;
     31 import static org.junit.Assert.*;
     32 import static org.mockito.Mockito.mock;
     33 import static org.mockito.Mockito.verify;
     34 
     35 @RunWith(WithTestDefaultsRunner.class)
     36 public class TextViewTest {
     37 
     38     private static final String INITIAL_TEXT = "initial text";
     39     private static final String NEW_TEXT = "new text";
     40     private TextView textView;
     41 
     42     @Before
     43     public void setUp() throws Exception {
     44         textView = new TextView(new Activity());
     45     }
     46 
     47     @Test
     48     public void shouldTriggerTheImeListener() {
     49         TextView textView = new TextView(null);
     50         TestOnEditorActionListener actionListener = new TestOnEditorActionListener();
     51         textView.setOnEditorActionListener(actionListener);
     52 
     53         shadowOf(textView).triggerEditorAction(EditorInfo.IME_ACTION_GO);
     54 
     55         assertThat(actionListener.textView, is(textView));
     56         assertThat(actionListener.sentImeId, equalTo(EditorInfo.IME_ACTION_GO));
     57     }
     58 
     59     @Test
     60     public void testGetUrls() throws Exception {
     61         textView.setText("here's some text http://google.com/\nblah\thttp://another.com/123?456 blah");
     62 
     63         assertThat(urlStringsFrom(textView.getUrls()), equalTo(asList(
     64                 "http://google.com/",
     65                 "http://another.com/123?456"
     66         )));
     67     }
     68 
     69     @Test
     70     public void testGetGravity() throws Exception {
     71         assertThat(textView.getGravity(), not(equalTo(Gravity.CENTER)));
     72         textView.setGravity(Gravity.CENTER);
     73         assertThat(textView.getGravity(), equalTo(Gravity.CENTER));
     74     }
     75 
     76     @Test
     77     public void testMovementMethod() {
     78         MovementMethod movement = new ArrowKeyMovementMethod();
     79 
     80         assertNull(textView.getMovementMethod());
     81         textView.setMovementMethod(movement);
     82         assertThat(textView.getMovementMethod(), sameInstance(movement));
     83     }
     84 
     85     @Test
     86     public void testLinksClickable() {
     87         assertThat(textView.getLinksClickable(), equalTo(false));
     88 
     89         textView.setLinksClickable(true);
     90         assertThat(textView.getLinksClickable(), equalTo(true));
     91 
     92         textView.setLinksClickable(false);
     93         assertThat(textView.getLinksClickable(), equalTo(false));
     94     }
     95 
     96     @Test
     97     public void testGetTextAppearanceId() throws Exception {
     98         TextView textView = new TextView(null);
     99         textView.setTextAppearance(null, 5);
    100 
    101         assertThat(shadowOf(textView).getTextAppearanceId(), equalTo(5));
    102     }
    103 
    104     @Test
    105     public void shouldSetTextAndTextColorWhileInflatingXmlLayout() throws Exception {
    106         Activity activity = new Activity();
    107         activity.setContentView(R.layout.text_views);
    108 
    109         TextView black = (TextView) activity.findViewById(R.id.black_text_view);
    110         assertThat(black.getText().toString(), equalTo("Black Text"));
    111         assertThat(shadowOf(black).getTextColorHexValue(), equalTo(0));
    112 
    113         TextView white = (TextView) activity.findViewById(R.id.white_text_view);
    114         assertThat(white.getText().toString(), equalTo("White Text"));
    115         assertThat(shadowOf(white).getTextColorHexValue(), equalTo(activity.getResources().getColor(android.R.color.white)));
    116 
    117         TextView grey = (TextView) activity.findViewById(R.id.grey_text_view);
    118         assertThat(grey.getText().toString(), equalTo("Grey Text"));
    119         assertThat(shadowOf(grey).getTextColorHexValue(), equalTo(activity.getResources().getColor(R.color.grey42)));
    120     }
    121 
    122     @Test
    123     public void shouldSetHintAndHintColorWhileInflatingXmlLayout() throws Exception {
    124         Activity activity = new Activity();
    125         activity.setContentView(R.layout.text_views_hints);
    126 
    127         TextView black = (TextView) activity.findViewById(R.id.black_text_view_hint);
    128         assertThat(black.getHint().toString(), equalTo("Black Hint"));
    129         assertThat(shadowOf(black).getHintColorHexValue(), equalTo(0));
    130 
    131         TextView white = (TextView) activity.findViewById(R.id.white_text_view_hint);
    132         assertThat(white.getHint().toString(), equalTo("White Hint"));
    133         assertThat(shadowOf(white).getHintColorHexValue(), equalTo(activity.getResources().getColor(android.R.color.white)));
    134 
    135         TextView grey = (TextView) activity.findViewById(R.id.grey_text_view_hint);
    136         assertThat(grey.getHint().toString(), equalTo("Grey Hint"));
    137         assertThat(shadowOf(grey).getHintColorHexValue(), equalTo(activity.getResources().getColor(R.color.grey42)));
    138     }
    139 
    140     @Test
    141     public void shouldNotHaveTransformationMethodByDefault() {
    142         ShadowTextView view = new ShadowTextView();
    143         assertThat(view.getTransformationMethod(), is(CoreMatchers.<Object>nullValue()));
    144     }
    145 
    146     @Test
    147     public void shouldAllowSettingATransformationMethod() {
    148         ShadowTextView view = new ShadowTextView();
    149         view.setTransformationMethod(new ShadowPasswordTransformationMethod());
    150         assertEquals(view.getTransformationMethod().getClass(), ShadowPasswordTransformationMethod.class);
    151     }
    152 
    153     @Test
    154     public void testGetInputType() throws Exception {
    155         assertThat(textView.getInputType(), not(equalTo(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD)));
    156         textView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
    157         assertThat(textView.getInputType(), equalTo(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD));
    158     }
    159 
    160     @Test
    161     public void givenATextViewWithATextWatcherAdded_WhenSettingTextWithTextResourceId_ShouldNotifyTextWatcher() {
    162         MockTextWatcher mockTextWatcher = new MockTextWatcher();
    163         textView.addTextChangedListener(mockTextWatcher);
    164 
    165         textView.setText(R.string.hello);
    166 
    167         assertEachTextWatcherEventWasInvoked(mockTextWatcher);
    168     }
    169 
    170     @Test
    171     public void givenATextViewWithATextWatcherAdded_WhenSettingTextWithCharSequence_ShouldNotifyTextWatcher() {
    172         MockTextWatcher mockTextWatcher = new MockTextWatcher();
    173         textView.addTextChangedListener(mockTextWatcher);
    174 
    175         textView.setText("text");
    176 
    177         assertEachTextWatcherEventWasInvoked(mockTextWatcher);
    178     }
    179 
    180     @Test
    181     public void givenATextViewWithATextWatcherAdded_WhenSettingNullText_ShouldNotifyTextWatcher() {
    182         MockTextWatcher mockTextWatcher = new MockTextWatcher();
    183         textView.addTextChangedListener(mockTextWatcher);
    184 
    185         textView.setText(null);
    186 
    187         assertEachTextWatcherEventWasInvoked(mockTextWatcher);
    188     }
    189 
    190     @Test
    191     public void givenATextViewWithMultipleTextWatchersAdded_WhenSettingText_ShouldNotifyEachTextWatcher() {
    192         List<MockTextWatcher> mockTextWatchers = anyNumberOfTextWatchers();
    193         for (MockTextWatcher textWatcher : mockTextWatchers) {
    194             textView.addTextChangedListener(textWatcher);
    195         }
    196 
    197         textView.setText("text");
    198 
    199         for (MockTextWatcher textWatcher : mockTextWatchers) {
    200             assertEachTextWatcherEventWasInvoked(textWatcher);
    201         }
    202     }
    203 
    204     @Test
    205     public void whenSettingText_ShouldFireBeforeTextChangedWithCorrectArguments() {
    206         textView.setText(INITIAL_TEXT);
    207         TextWatcher mockTextWatcher = mock(TextWatcher.class);
    208         textView.addTextChangedListener(mockTextWatcher);
    209 
    210         textView.setText(NEW_TEXT);
    211 
    212         verify(mockTextWatcher).beforeTextChanged(INITIAL_TEXT, 0, INITIAL_TEXT.length(), NEW_TEXT.length());
    213     }
    214 
    215     @Test
    216     public void whenSettingText_ShouldFireOnTextChangedWithCorrectArguments() {
    217         textView.setText(INITIAL_TEXT);
    218         TextWatcher mockTextWatcher = mock(TextWatcher.class);
    219         textView.addTextChangedListener(mockTextWatcher);
    220 
    221         textView.setText(NEW_TEXT);
    222 
    223         verify(mockTextWatcher).onTextChanged(NEW_TEXT, 0, INITIAL_TEXT.length(), NEW_TEXT.length());
    224     }
    225 
    226     @Test
    227     public void whenSettingText_ShouldFireAfterTextChangedWithCorrectArgument() {
    228         MockTextWatcher mockTextWatcher = new MockTextWatcher();
    229         textView.addTextChangedListener(mockTextWatcher);
    230 
    231         textView.setText(NEW_TEXT);
    232 
    233         assertThat(mockTextWatcher.afterTextChangeArgument.toString(), equalTo(NEW_TEXT));
    234     }
    235 
    236     @Test
    237     public void whenAppendingText_ShouldAppendNewTextAfterOldOne() {
    238         textView.setText(INITIAL_TEXT);
    239         textView.append(NEW_TEXT);
    240 
    241         assertEquals(INITIAL_TEXT + NEW_TEXT, textView.getText());
    242     }
    243 
    244     @Test
    245     public void whenAppendingText_ShouldFireBeforeTextChangedWithCorrectArguments() {
    246         textView.setText(INITIAL_TEXT);
    247         TextWatcher mockTextWatcher = mock(TextWatcher.class);
    248         textView.addTextChangedListener(mockTextWatcher);
    249 
    250         textView.append(NEW_TEXT);
    251 
    252         verify(mockTextWatcher).beforeTextChanged(INITIAL_TEXT, 0, INITIAL_TEXT.length(), INITIAL_TEXT.length() + NEW_TEXT.length());
    253     }
    254 
    255     @Test
    256     public void whenAppendingText_ShouldFireOnTextChangedWithCorrectArguments() {
    257         textView.setText(INITIAL_TEXT);
    258         TextWatcher mockTextWatcher = mock(TextWatcher.class);
    259         textView.addTextChangedListener(mockTextWatcher);
    260 
    261         textView.append(NEW_TEXT);
    262 
    263         verify(mockTextWatcher).onTextChanged(INITIAL_TEXT + NEW_TEXT, 0, INITIAL_TEXT.length(), INITIAL_TEXT.length() + NEW_TEXT.length());
    264     }
    265 
    266     @Test
    267     public void whenAppendingText_ShouldFireAfterTextChangedWithCorrectArgument() {
    268         textView.setText(INITIAL_TEXT);
    269         MockTextWatcher mockTextWatcher = new MockTextWatcher();
    270         textView.addTextChangedListener(mockTextWatcher);
    271 
    272         textView.append(NEW_TEXT);
    273 
    274         assertThat(mockTextWatcher.afterTextChangeArgument.toString(), equalTo(INITIAL_TEXT + NEW_TEXT));
    275     }
    276 
    277     @Test
    278     public void removeTextChangedListener_shouldRemoveTheListener() throws Exception {
    279         MockTextWatcher watcher = new MockTextWatcher();
    280         textView.addTextChangedListener(watcher);
    281         assertTrue(shadowOf(textView).getWatchers().contains(watcher));
    282 
    283         textView.removeTextChangedListener(watcher);
    284         assertFalse(shadowOf(textView).getWatchers().contains(watcher));
    285     }
    286 
    287     @Test
    288     public void getPaint_returnsMeasureTextEnabledObject() throws Exception {
    289         assertThat(textView.getPaint().measureText("12345"), equalTo(5f));
    290     }
    291 
    292     @Test
    293     public void append_whenSelectionIsAtTheEnd_shouldKeepSelectionAtTheEnd() throws Exception {
    294         textView.setText("1");
    295         shadowOf(textView).setSelection(0, 0);
    296         textView.append("2");
    297         assertEquals(0, textView.getSelectionEnd());
    298         assertEquals(0, textView.getSelectionStart());
    299 
    300         shadowOf(textView).setSelection(2, 2);
    301         textView.append("3");
    302         assertEquals(3, textView.getSelectionEnd());
    303         assertEquals(3, textView.getSelectionStart());
    304     }
    305 
    306     @Test
    307     public void append_whenSelectionReachesToEnd_shouldExtendSelectionToTheEnd() throws Exception {
    308         textView.setText("12");
    309         shadowOf(textView).setSelection(0, 2);
    310         textView.append("3");
    311         assertEquals(3, textView.getSelectionEnd());
    312         assertEquals(0, textView.getSelectionStart());
    313     }
    314 
    315     @Test
    316     public void testSetCompountDrawablesWithIntrinsicBounds_int_shouldCreateDrawablesWithResourceIds() throws Exception {
    317         textView.setCompoundDrawablesWithIntrinsicBounds(6, 7, 8, 9);
    318 
    319         Assert.assertEquals(6, shadowOf(textView.getCompoundDrawables()[0]).getLoadedFromResourceId());
    320         Assert.assertEquals(7, shadowOf(textView.getCompoundDrawables()[1]).getLoadedFromResourceId());
    321         Assert.assertEquals(8, shadowOf(textView.getCompoundDrawables()[2]).getLoadedFromResourceId());
    322         Assert.assertEquals(9, shadowOf(textView.getCompoundDrawables()[3]).getLoadedFromResourceId());
    323     }
    324 
    325     @Test
    326     public void testSetCompountDrawablesWithIntrinsicBounds_int_shouldNotCreateDrawablesForZero() throws Exception {
    327         textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
    328 
    329         Assert.assertNull(textView.getCompoundDrawables()[0]);
    330         Assert.assertNull(textView.getCompoundDrawables()[1]);
    331         Assert.assertNull(textView.getCompoundDrawables()[2]);
    332         Assert.assertNull(textView.getCompoundDrawables()[3]);
    333     }
    334 
    335     @Test
    336     public void canSetAndGetTypeface() throws Exception {
    337         Typeface typeface = Robolectric.newInstanceOf(Typeface.class);
    338         textView.setTypeface(typeface);
    339         Assert.assertEquals(typeface, textView.getTypeface());
    340     }
    341 
    342     @Test
    343     public void onTouchEvent_shouldCallMovementMethodOnTouchEventWithSetMotionEvent() throws Exception {
    344         TestMovementMethod testMovementMethod = new TestMovementMethod();
    345 
    346         textView.setMovementMethod(testMovementMethod);
    347         MotionEvent event = MotionEvent.obtain(0, 0, 0, 0, 0, 0);
    348         textView.dispatchTouchEvent(event);
    349 
    350         assertEquals(testMovementMethod.event, event);
    351     }
    352 
    353     @Test
    354     public void canSetAndGetLayout() throws Exception {
    355         StaticLayout layout = new StaticLayout(null, null, 0, null, 0, 0, true);
    356         shadowOf(textView).setLayout(layout);
    357         assertEquals(textView.getLayout(), layout);
    358     }
    359 
    360     @Test
    361     public void testGetError() {
    362       assertNull(textView.getError());
    363       CharSequence error = "myError";
    364       textView.setError(error);
    365       assertEquals(error, textView.getError());
    366     }
    367 
    368     private List<MockTextWatcher> anyNumberOfTextWatchers() {
    369         List<MockTextWatcher> mockTextWatchers = new ArrayList<MockTextWatcher>();
    370         int numberBetweenOneAndTen = new Random().nextInt(10) + 1;
    371         for (int i = 0; i < numberBetweenOneAndTen; i++) {
    372             mockTextWatchers.add(new MockTextWatcher());
    373         }
    374         return mockTextWatchers;
    375     }
    376 
    377     private void assertEachTextWatcherEventWasInvoked(MockTextWatcher mockTextWatcher) {
    378         assertTrue("Expected each TextWatcher event to have been invoked once", mockTextWatcher.methodsCalled.size() == 3);
    379 
    380         assertThat(mockTextWatcher.methodsCalled.get(0), equalTo("beforeTextChanged"));
    381         assertThat(mockTextWatcher.methodsCalled.get(1), equalTo("onTextChanged"));
    382         assertThat(mockTextWatcher.methodsCalled.get(2), equalTo("afterTextChanged"));
    383     }
    384 
    385     private List<String> urlStringsFrom(URLSpan[] urlSpans) {
    386         List<String> urls = new ArrayList<String>();
    387         for (URLSpan urlSpan : urlSpans) {
    388             urls.add(urlSpan.getURL());
    389         }
    390         return urls;
    391     }
    392 
    393     private static class TestOnEditorActionListener implements TextView.OnEditorActionListener {
    394         private TextView textView;
    395         private int sentImeId;
    396 
    397         @Override
    398         public boolean onEditorAction(TextView textView, int sentImeId, KeyEvent keyEvent) {
    399             this.textView = textView;
    400             this.sentImeId = sentImeId;
    401             return false;
    402         }
    403     }
    404 
    405     private static class MockTextWatcher implements TextWatcher {
    406 
    407         List<String> methodsCalled = new ArrayList<String>();
    408         Editable afterTextChangeArgument;
    409 
    410         @Override
    411         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    412             methodsCalled.add("beforeTextChanged");
    413         }
    414 
    415         @Override
    416         public void onTextChanged(CharSequence s, int start, int before, int count) {
    417             methodsCalled.add("onTextChanged");
    418         }
    419 
    420         @Override
    421         public void afterTextChanged(Editable s) {
    422             methodsCalled.add("afterTextChanged");
    423             afterTextChangeArgument = s;
    424         }
    425 
    426     }
    427 
    428     private static class TestMovementMethod implements MovementMethod {
    429         public MotionEvent event;
    430         public boolean touchEventWasCalled;
    431 
    432         @Override
    433         public void initialize(TextView widget, Spannable text) {
    434         }
    435 
    436         @Override
    437         public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event) {
    438             return false;
    439         }
    440 
    441         @Override
    442         public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event) {
    443             return false;
    444         }
    445 
    446         @Override
    447         public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
    448             return false;
    449         }
    450 
    451         @Override
    452         public void onTakeFocus(TextView widget, Spannable text, int direction) {
    453         }
    454 
    455         @Override
    456         public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
    457             return false;
    458         }
    459 
    460         @Override
    461         public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) {
    462             this.event = event;
    463             touchEventWasCalled = true;
    464             return false;
    465         }
    466 
    467         @Override
    468         public boolean canSelectArbitrarily() {
    469             return false;
    470         }
    471 
    472 		@Override
    473 		public boolean onGenericMotionEvent(TextView widget, Spannable text,
    474 				MotionEvent event) {
    475 			return false;
    476 		}
    477     }
    478 }
    479