Home | History | Annotate | Download | only in shadows
      1 package com.xtremelabs.robolectric.shadows;
      2 
      3 import android.app.Activity;
      4 import android.content.Context;
      5 import android.graphics.Point;
      6 import android.graphics.Rect;
      7 import android.graphics.drawable.ColorDrawable;
      8 import android.view.*;
      9 import android.view.View.MeasureSpec;
     10 import android.view.animation.Animation;
     11 import android.widget.LinearLayout;
     12 import com.xtremelabs.robolectric.R;
     13 import com.xtremelabs.robolectric.Robolectric;
     14 import com.xtremelabs.robolectric.WithTestDefaultsRunner;
     15 import com.xtremelabs.robolectric.util.*;
     16 import org.junit.Before;
     17 import org.junit.Test;
     18 import org.junit.runner.RunWith;
     19 
     20 import static com.xtremelabs.robolectric.Robolectric.shadowOf;
     21 import static junit.framework.Assert.assertEquals;
     22 import static org.hamcrest.CoreMatchers.*;
     23 import static org.hamcrest.MatcherAssert.assertThat;
     24 import static org.junit.Assert.*;
     25 
     26 @RunWith(WithTestDefaultsRunner.class)
     27 public class ViewTest {
     28     private View view;
     29 
     30     @Before
     31     public void setUp() throws Exception {
     32         view = new View(new Activity());
     33     }
     34 
     35     @Test
     36     public void testHasEmptyLayoutParams() throws Exception {
     37         ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
     38         assertThat(layoutParams, notNullValue());
     39     }
     40 
     41     @Test
     42     public void layout_shouldAffectWidthAndHeight() throws Exception {
     43         assertThat(view.getWidth(), equalTo(0));
     44         assertThat(view.getHeight(), equalTo(0));
     45 
     46         view.layout(100, 200, 303, 404);
     47         assertThat(view.getWidth(), equalTo(303 - 100));
     48         assertThat(view.getHeight(), equalTo(404 - 200));
     49     }
     50 
     51     @Test
     52     public void shouldFocus() throws Exception {
     53         final Transcript transcript = new Transcript();
     54 
     55         view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
     56             @Override
     57             public void onFocusChange(View v, boolean hasFocus) {
     58                 transcript.add(hasFocus ? "Gained focus" : "Lost focus");
     59             }
     60         });
     61 
     62         assertFalse(view.isFocused());
     63         assertFalse(view.hasFocus());
     64         transcript.assertNoEventsSoFar();
     65 
     66         view.requestFocus();
     67         assertTrue(view.isFocused());
     68         assertTrue(view.hasFocus());
     69         transcript.assertEventsSoFar("Gained focus");
     70 
     71         view.clearFocus();
     72         assertFalse(view.isFocused());
     73         assertFalse(view.hasFocus());
     74         transcript.assertEventsSoFar("Lost focus");
     75     }
     76 
     77     @Test
     78     public void shouldNotBeFocusableByDefault() throws Exception {
     79         assertFalse(view.isFocusable());
     80 
     81         view.setFocusable(true);
     82         assertTrue(view.isFocusable());
     83     }
     84 
     85     @Test
     86     public void shouldKnowIfThisOrAncestorsAreVisible() throws Exception {
     87         assertTrue(shadowOf(view).derivedIsVisible());
     88 
     89         ViewGroup grandParent = new LinearLayout(null);
     90         ViewGroup parent = new LinearLayout(null);
     91         grandParent.addView(parent);
     92         parent.addView(view);
     93 
     94         grandParent.setVisibility(View.GONE);
     95 
     96         assertFalse(shadowOf(view).derivedIsVisible());
     97     }
     98 
     99     @Test
    100     public void shouldInflateMergeRootedLayoutAndNotCreateReferentialLoops() throws Exception {
    101         LinearLayout root = new LinearLayout(null);
    102         root.inflate(new Activity(), R.layout.inner_merge, root);
    103         for (int i = 0; i < root.getChildCount(); i++) {
    104             View child = root.getChildAt(i);
    105             assertNotSame(root, child);
    106         }
    107     }
    108 
    109     @Test
    110     public void performLongClick_shouldClickOnView() throws Exception {
    111         TestOnLongClickListener clickListener = new TestOnLongClickListener();
    112         view.setOnLongClickListener(clickListener);
    113         shadowOf(view).performLongClick();
    114 
    115         assertTrue(clickListener.clicked);
    116     }
    117 
    118     @Test
    119     public void checkedClick_shouldClickOnView() throws Exception {
    120         TestOnClickListener clickListener = new TestOnClickListener();
    121         view.setOnClickListener(clickListener);
    122         shadowOf(view).checkedPerformClick();
    123 
    124         assertTrue(clickListener.clicked);
    125     }
    126 
    127     @Test(expected = RuntimeException.class)
    128     public void checkedClick_shouldThrowIfViewIsNotVisible() throws Exception {
    129         ViewGroup grandParent = new LinearLayout(null);
    130         ViewGroup parent = new LinearLayout(null);
    131         grandParent.addView(parent);
    132         parent.addView(view);
    133         grandParent.setVisibility(View.GONE);
    134 
    135         shadowOf(view).checkedPerformClick();
    136     }
    137 
    138     @Test(expected = RuntimeException.class)
    139     public void checkedClick_shouldThrowIfViewIsDisabled() throws Exception {
    140         view.setEnabled(false);
    141         shadowOf(view).checkedPerformClick();
    142     }
    143 
    144     @Test
    145     public void getBackground_shouldReturnNullIfNoBackgroundHasBeenSet() throws Exception {
    146         assertThat(view.getBackground(), nullValue());
    147     }
    148 
    149     @Test
    150     public void shouldSetBackgroundColor() {
    151         view.setBackgroundColor(R.color.android_red);
    152         int intColor = view.getResources().getColor(R.color.android_red);
    153 
    154         assertThat((ColorDrawable) view.getBackground(), equalTo(new ColorDrawable(intColor)));
    155     }
    156 
    157     @Test
    158     public void shouldSetBackgroundResource() throws Exception {
    159         view.setBackgroundResource(R.drawable.an_image);
    160         assertThat(view.getBackground(), equalTo(view.getResources().getDrawable(R.drawable.an_image)));
    161     }
    162 
    163     @Test
    164     public void shouldRecordBackgroundColor() {
    165         int[] colors = {0, 1, 727};
    166 
    167         for (int color : colors) {
    168             view.setBackgroundColor(color);
    169             assertThat(shadowOf(view).getBackgroundColor(), equalTo(color));
    170         }
    171     }
    172 
    173     @Test
    174     public void shouldPostActionsToTheMessageQueue() throws Exception {
    175         Robolectric.pauseMainLooper();
    176 
    177         TestRunnable runnable = new TestRunnable();
    178         view.post(runnable);
    179         assertFalse(runnable.wasRun);
    180 
    181         Robolectric.unPauseMainLooper();
    182         assertTrue(runnable.wasRun);
    183     }
    184 
    185     @Test
    186     public void shouldPostInvalidateDelayed() throws Exception {
    187         Robolectric.pauseMainLooper();
    188 
    189         view.postInvalidateDelayed(100);
    190         ShadowView shadowView = shadowOf(view);
    191         assertFalse(shadowView.wasInvalidated());
    192 
    193         Robolectric.unPauseMainLooper();
    194         assertTrue(shadowView.wasInvalidated());
    195     }
    196 
    197     @Test
    198     public void shouldPostActionsToTheMessageQueueWithDelay() throws Exception {
    199         Robolectric.pauseMainLooper();
    200 
    201         TestRunnable runnable = new TestRunnable();
    202         view.postDelayed(runnable, 1);
    203         assertFalse(runnable.wasRun);
    204 
    205         Robolectric.getUiThreadScheduler().advanceBy(1);
    206         assertTrue(runnable.wasRun);
    207     }
    208 
    209     @Test
    210     public void shouldSupportAllConstructors() throws Exception {
    211         new View(null);
    212         new View(null, null);
    213         new View(null, null, 0);
    214     }
    215 
    216     @Test
    217     public void shouldSetAnimation() throws Exception {
    218         Animation anim = new TestAnimation();
    219         view.setAnimation(anim);
    220         assertThat(view.getAnimation(), sameInstance(anim));
    221     }
    222 
    223     @Test
    224     public void shouldStartAndClearAnimation() throws Exception {
    225         Animation anim = new TestAnimation();
    226         TestAnimationListener listener = new TestAnimationListener();
    227         anim.setAnimationListener(listener);
    228         assertThat(listener.wasStartCalled, equalTo(false));
    229         assertThat(listener.wasRepeatCalled, equalTo(false));
    230         assertThat(listener.wasEndCalled, equalTo(false));
    231         view.startAnimation(anim);
    232         assertThat(listener.wasStartCalled, equalTo(true));
    233         assertThat(listener.wasRepeatCalled, equalTo(false));
    234         assertThat(listener.wasEndCalled, equalTo(false));
    235         view.clearAnimation();
    236         assertThat(listener.wasStartCalled, equalTo(true));
    237         assertThat(listener.wasRepeatCalled, equalTo(false));
    238         assertThat(listener.wasEndCalled, equalTo(true));
    239     }
    240 
    241     @Test
    242     public void shouldFindViewWithTag() {
    243         view.setTag("tagged");
    244         assertThat(view.findViewWithTag("tagged"), sameInstance(view));
    245     }
    246 
    247     @Test
    248     public void shouldFindViewWithTag_whenViewOverridesGetTag() throws Exception {
    249         View view = new View(Robolectric.application) {
    250             @Override
    251             public Object getTag() {
    252                 return "blarg";
    253             }
    254         };
    255         assertThat(view.findViewWithTag("blarg"), sameInstance(view));
    256     }
    257 
    258     @Test
    259     public void scrollTo_shouldStoreTheScrolledCoordinates() throws Exception {
    260         view.scrollTo(1, 2);
    261         assertThat(shadowOf(view).scrollToCoordinates, equalTo(new Point(1, 2)));
    262     }
    263 
    264     @Test
    265     public void shouldScrollTo() throws Exception {
    266         view.scrollTo(7, 6);
    267 
    268         assertEquals(7, view.getScrollX());
    269         assertEquals(6, view.getScrollY());
    270     }
    271 
    272     @Test
    273     public void shouldGetScrollXAndY() {
    274         assertEquals(0, view.getScrollX());
    275         assertEquals(0, view.getScrollY());
    276     }
    277 
    278     @Test
    279     public void getViewTreeObserver_shouldReturnTheSameObserverFromMultipleCalls() throws Exception {
    280         ViewTreeObserver observer = view.getViewTreeObserver();
    281         assertThat(observer, instanceOf(ViewTreeObserver.class));
    282         assertThat(view.getViewTreeObserver(), sameInstance(observer));
    283     }
    284 
    285     @Test
    286     public void dispatchTouchEvent_sendsMotionEventToOnTouchEvent() throws Exception {
    287         TouchableView touchableView = new TouchableView(null);
    288         MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0);
    289         touchableView.dispatchTouchEvent(event);
    290         assertThat(touchableView.event, sameInstance(event));
    291         view.dispatchTouchEvent(event);
    292         assertThat(shadowOf(view).getLastTouchEvent(), sameInstance(event));
    293     }
    294 
    295     @Test
    296     public void dispatchTouchEvent_listensToTrueFromListener() throws Exception {
    297         view.setOnTouchListener(new View.OnTouchListener() {
    298             @Override
    299             public boolean onTouch(View view, MotionEvent motionEvent) {
    300                 return true;
    301             }
    302         });
    303         MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0);
    304         view.dispatchTouchEvent(event);
    305         assertThat(shadowOf(view).getLastTouchEvent(), nullValue());
    306     }
    307 
    308     @Test
    309     public void dispatchTouchEvent_listensToFalseFromListener() throws Exception {
    310         view.setOnTouchListener(new View.OnTouchListener() {
    311             @Override
    312             public boolean onTouch(View view, MotionEvent motionEvent) {
    313                 return false;
    314             }
    315         });
    316         MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0);
    317         view.dispatchTouchEvent(event);
    318         assertThat(shadowOf(view).getLastTouchEvent(), sameInstance(event));
    319     }
    320 
    321     @Test
    322     public void dispatchFocusEvent_sendsFocusToOnFocusChanged() throws Exception {
    323         FocusableView focusableView = new FocusableView(null);
    324         focusableView.requestFocus();
    325         assertThat(focusableView.onFocusChangedWasCalled, equalTo(true));
    326     }
    327 
    328     @Test
    329     public void test_nextFocusDownId() throws Exception {
    330         assertEquals(View.NO_ID, view.getNextFocusDownId());
    331 
    332         view.setNextFocusDownId(R.id.icon);
    333         assertEquals(R.id.icon, view.getNextFocusDownId());
    334     }
    335 
    336     @Test
    337     public void dispatchOnAnimationEnd() throws Exception {
    338         TestView view1 = new TestView(new Activity());
    339         assertFalse(view1.onAnimationEndWasCalled);
    340         shadowOf(view1).finishedAnimation();
    341         assertTrue(view1.onAnimationEndWasCalled);
    342     }
    343 
    344     @Test
    345     public void test_measuredDimension() {
    346     	// View does not provide its own onMeasure implementation
    347     	TestView view1 = new TestView(new Activity());
    348 
    349     	assertThat(view1.getHeight(), equalTo(0));
    350     	assertThat(view1.getWidth(), equalTo(0));
    351     	assertThat(view1.getMeasuredHeight(), equalTo(0));
    352     	assertThat(view1.getMeasuredWidth(), equalTo(0));
    353 
    354     	view1.measure( MeasureSpec.makeMeasureSpec(150, MeasureSpec.AT_MOST),
    355     				   MeasureSpec.makeMeasureSpec(300, MeasureSpec.AT_MOST) );
    356 
    357     	assertThat(view1.getHeight(), equalTo(0));
    358     	assertThat(view1.getWidth(), equalTo(0));
    359     	assertThat(view1.getMeasuredHeight(), equalTo(300));
    360     	assertThat(view1.getMeasuredWidth(), equalTo(150));
    361     }
    362 
    363     @Test
    364     public void test_measuredDimensionCustomView() {
    365        	// View provides its own onMeasure implementation
    366     	TestView2 view2 = new TestView2(new Activity());
    367 
    368     	assertThat(view2.getHeight(), equalTo(0));
    369     	assertThat(view2.getWidth(), equalTo(0));
    370     	assertThat(view2.getMeasuredHeight(), equalTo(0));
    371     	assertThat(view2.getMeasuredWidth(), equalTo(0));
    372 
    373     	view2.measure( MeasureSpec.makeMeasureSpec(1000, MeasureSpec.AT_MOST),
    374     				   MeasureSpec.makeMeasureSpec(600, MeasureSpec.AT_MOST) );
    375 
    376     	assertThat(view2.getHeight(), equalTo(0));
    377     	assertThat(view2.getWidth(), equalTo(0));
    378     	assertThat(view2.getMeasuredHeight(), equalTo(400));
    379     	assertThat(view2.getMeasuredWidth(), equalTo(800));
    380     }
    381 
    382     @Test
    383     public void testFilterTouchesWhenObscured() {
    384         assertFalse(view.getFilterTouchesWhenObscured());
    385 
    386         view.setFilterTouchesWhenObscured(true);
    387         assertTrue(view.getFilterTouchesWhenObscured());
    388 
    389         view.setFilterTouchesWhenObscured(false);
    390         assertFalse(view.getFilterTouchesWhenObscured());
    391     }
    392 
    393     @Test
    394     public void testFilterTouchesWhenObscuredWhenLoadedFromXml() {
    395         LinearLayout root = new LinearLayout(null);
    396         ShadowView.inflate(new Activity(), R.layout.views, root);
    397 
    398         View defaultView = root.findViewById(R.id.default_view);
    399         assertFalse(defaultView.getFilterTouchesWhenObscured());
    400 
    401         View filterFalseView = root.findViewById(R.id.filter_touches_false_view);
    402         assertFalse(filterFalseView.getFilterTouchesWhenObscured());
    403 
    404         View filterTrueView = root.findViewById(R.id.filter_touches_true_view);
    405         assertTrue(filterTrueView.getFilterTouchesWhenObscured());
    406     }
    407 
    408     @Test
    409     public void testClickable() {
    410         assertFalse(view.isClickable());
    411 
    412         view.setClickable(true);
    413         assertTrue(view.isClickable());
    414 
    415         view.setClickable(false);
    416         assertFalse(view.isClickable());
    417     }
    418 
    419     @Test
    420     public void testClickableWhenLoadedFromXml() {
    421         LinearLayout root = new LinearLayout(null);
    422         ShadowView.inflate(new Activity(), R.layout.views, root);
    423 
    424         View defaultView = root.findViewById(R.id.default_view);
    425         assertFalse(defaultView.isClickable());
    426 
    427         View clickableFalseView = root.findViewById(R.id.clickable_false_view);
    428         assertFalse(clickableFalseView.isClickable());
    429 
    430         View clickableTrueView = root.findViewById(R.id.clickable_true_view);
    431         assertTrue(clickableTrueView.isClickable());
    432     }
    433 
    434     @Test
    435     public void testFocusable() {
    436         assertFalse(view.isFocusable());
    437 
    438         view.setFocusable(true);
    439         assertTrue(view.isFocusable());
    440 
    441         view.setFocusable(false);
    442         assertFalse(view.isFocusable());
    443     }
    444 
    445     @Test
    446     public void testFocusableWhenLoadedFromXml() {
    447         LinearLayout root = new LinearLayout(null);
    448         ShadowView.inflate(new Activity(), R.layout.views, root);
    449 
    450         View defaultView = root.findViewById(R.id.default_view);
    451         assertFalse(defaultView.isFocusable());
    452 
    453         View focusableFalseView = root.findViewById(R.id.focusable_false_view);
    454         assertFalse(focusableFalseView.isFocusable());
    455 
    456         View focusableTrueView = root.findViewById(R.id.focusable_true_view);
    457         assertTrue(focusableTrueView.isFocusable());
    458     }
    459 
    460     private static class TestAnimation extends Animation {
    461     }
    462 
    463     private static class TouchableView extends View {
    464         MotionEvent event;
    465 
    466         public TouchableView(Context context) {
    467             super(context);
    468         }
    469 
    470         @Override
    471         public boolean onTouchEvent(MotionEvent event) {
    472             this.event = event;
    473             return false;
    474         }
    475     }
    476 
    477     private static class TestView extends View {
    478         boolean onAnimationEndWasCalled;
    479 
    480         public TestView(Context context) {
    481             super(context);
    482         }
    483 
    484         @Override
    485         protected void onAnimationEnd() {
    486             super.onAnimationEnd();
    487             onAnimationEndWasCalled = true;
    488         }
    489     }
    490 
    491     private static class FocusableView extends View {
    492       boolean onFocusChangedWasCalled;
    493 
    494       public FocusableView(Context context) {
    495         super(context);
    496       }
    497 
    498       @Override
    499       protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
    500         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
    501 
    502         onFocusChangedWasCalled = true;
    503       }
    504     }
    505 
    506     private static class TestView2 extends View {
    507     	public TestView2(Context context) {
    508             super(context);
    509         }
    510 
    511 		@Override
    512 		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    513 			super.onMeasure(800, 400);
    514 		}
    515     }
    516 }
    517