Home | History | Annotate | Download | only in robolectric
      1 package org.robolectric;
      2 
      3 import static org.assertj.core.api.Assertions.assertThat;
      4 import static org.junit.Assert.assertEquals;
      5 import static org.junit.Assert.assertFalse;
      6 import static org.junit.Assert.assertNull;
      7 import static org.junit.Assert.assertTrue;
      8 import static org.mockito.Mockito.mock;
      9 
     10 import java.lang.reflect.Method;
     11 import java.lang.reflect.Modifier;
     12 import org.assertj.core.api.Assertions;
     13 import org.junit.Test;
     14 import org.junit.runner.RunWith;
     15 import org.robolectric.annotation.Implementation;
     16 import org.robolectric.annotation.Implements;
     17 import org.robolectric.annotation.internal.Instrument;
     18 import org.robolectric.internal.SandboxTestRunner;
     19 import org.robolectric.internal.bytecode.SandboxConfig;
     20 import org.robolectric.internal.bytecode.ShadowConstants;
     21 import org.robolectric.shadow.api.Shadow;
     22 import org.robolectric.testing.AnUninstrumentedClass;
     23 import org.robolectric.testing.Pony;
     24 
     25 @RunWith(SandboxTestRunner.class)
     26 public class ShadowingTest {
     27 
     28   @Test
     29   @SandboxConfig(shadows = {ShadowAccountManagerForTests.class})
     30   public void testStaticMethodsAreDelegated() throws Exception {
     31     Object arg = mock(Object.class);
     32     AccountManager.get(arg);
     33     assertThat(ShadowAccountManagerForTests.wasCalled).isTrue();
     34     assertThat(ShadowAccountManagerForTests.arg).isSameAs(arg);
     35   }
     36 
     37   @Implements(AccountManager.class)
     38   public static class ShadowAccountManagerForTests {
     39     public static boolean wasCalled = false;
     40     public static Object arg;
     41 
     42     public static AccountManager get(Object arg) {
     43       wasCalled = true;
     44       ShadowAccountManagerForTests.arg = arg;
     45       return mock(AccountManager.class);
     46     }
     47   }
     48 
     49   static class Context {
     50   }
     51 
     52   static class AccountManager {
     53     public static AccountManager get(Object arg) {
     54       return null;
     55     }
     56   }
     57 
     58   @Test
     59   @SandboxConfig(shadows = {ShadowClassWithProtectedMethod.class})
     60   public void testProtectedMethodsAreDelegated() throws Exception {
     61     ClassWithProtectedMethod overlay = new ClassWithProtectedMethod();
     62     assertEquals("shadow name", overlay.getName());
     63   }
     64 
     65   @Implements(ClassWithProtectedMethod.class)
     66   public static class ShadowClassWithProtectedMethod {
     67     @Implementation
     68     protected String getName() {
     69       return "shadow name";
     70     }
     71   }
     72 
     73   @Instrument
     74   public static class ClassWithProtectedMethod {
     75     protected String getName() {
     76       return "protected name";
     77     }
     78   }
     79 
     80   @Test
     81   @SandboxConfig(shadows = {ShadowPaintForTests.class})
     82   public void testNativeMethodsAreDelegated() throws Exception {
     83     Paint paint = new Paint();
     84     paint.setColor(1234);
     85 
     86     Assertions.assertThat(paint.getColor()).isEqualTo(1234);
     87   }
     88 
     89   @Instrument
     90   static class Paint {
     91     public native void setColor(int color);
     92     public native int getColor();
     93   }
     94 
     95   @Implements(Paint.class)
     96   public static class ShadowPaintForTests {
     97     private int color;
     98 
     99     @Implementation
    100     protected void setColor(int color) {
    101       this.color = color;
    102     }
    103 
    104     @Implementation
    105     protected int getColor() {
    106       return color;
    107     }
    108   }
    109 
    110   @Implements(ClassWithNoDefaultConstructor.class)
    111   public static class ShadowForClassWithNoDefaultConstructor {
    112     public static boolean shadowDefaultConstructorCalled = false;
    113     public static boolean shadowDefaultConstructorImplementorCalled = false;
    114 
    115     public ShadowForClassWithNoDefaultConstructor() {
    116       shadowDefaultConstructorCalled = true;
    117     }
    118 
    119     @Implementation
    120     protected void __constructor__() {
    121       shadowDefaultConstructorImplementorCalled = true;
    122     }
    123   }
    124 
    125   @Instrument @SuppressWarnings({"UnusedDeclaration"})
    126   public static class ClassWithNoDefaultConstructor {
    127     ClassWithNoDefaultConstructor(String string) {
    128     }
    129   }
    130 
    131   @Test
    132   @SandboxConfig(shadows = {Pony.ShadowPony.class})
    133   public void directlyOn_shouldCallThroughToOriginalMethodBody() throws Exception {
    134     Pony pony = new Pony();
    135 
    136     assertEquals("Fake whinny! You're on my neck!", pony.ride("neck"));
    137     assertEquals("Whinny! You're on my neck!", Shadow.directlyOn(pony, Pony.class).ride("neck"));
    138 
    139     assertEquals("Fake whinny! You're on my haunches!", pony.ride("haunches"));
    140   }
    141 
    142   @Test
    143   @SandboxConfig(shadows = {Pony.ShadowPony.class})
    144   public void shouldCallRealForUnshadowedMethod() throws Exception {
    145     assertEquals("Off I saunter to the salon!", new Pony().saunter("the salon"));
    146   }
    147 
    148   static class TextView {
    149   }
    150 
    151   static class ColorStateList {
    152     public ColorStateList(int[][] ints, int[] ints1) {
    153     }
    154   }
    155 
    156   static class TypedArray {
    157   }
    158 
    159   @Implements(TextView.class)
    160   public static class TextViewWithDummyGetTextColorsMethod {
    161     public static ColorStateList getTextColors(Context context, TypedArray attrs) {
    162       return new ColorStateList(new int[0][0], new int[0]);
    163     }
    164   }
    165 
    166   @Test
    167   @SandboxConfig(shadows = ShadowOfClassWithSomeConstructors.class)
    168   public void shouldGenerateSeparatedConstructorBodies() throws Exception {
    169     ClassWithSomeConstructors o = new ClassWithSomeConstructors("my name");
    170     assertNull(o.name);
    171 
    172     Method realConstructor = o.getClass().getDeclaredMethod(ShadowConstants.CONSTRUCTOR_METHOD_NAME, String.class);
    173     realConstructor.setAccessible(true);
    174     realConstructor.invoke(o, "my name");
    175     assertEquals("my name", o.name);
    176   }
    177 
    178   @Instrument
    179   public static class ClassWithSomeConstructors {
    180     public String name;
    181 
    182     public ClassWithSomeConstructors(String name) {
    183       this.name = name;
    184     }
    185   }
    186 
    187   @Implements(ClassWithSomeConstructors.class)
    188   public static class ShadowOfClassWithSomeConstructors {
    189     @Implementation
    190     protected void __constructor__(String s) {
    191     }
    192   }
    193 
    194   @Test
    195   @SandboxConfig(shadows = {ShadowApiImplementedClass.class})
    196   public void withNonApiSubclassesWhichExtendApi_shouldStillBeInvoked() throws Exception {
    197     assertEquals("did foo", new NonApiSubclass().doSomething("foo"));
    198   }
    199 
    200   public static class NonApiSubclass extends ApiImplementedClass {
    201     public String doSomething(String value) {
    202       return "did " + value;
    203     }
    204   }
    205 
    206   @Instrument
    207   public static class ApiImplementedClass {
    208   }
    209 
    210   @Implements(ApiImplementedClass.class)
    211   public static class ShadowApiImplementedClass {
    212   }
    213 
    214   @Test
    215   public void shouldNotInstrumentClassIfNotAddedToConfig() {
    216     assertEquals(1, new NonInstrumentedClass().plus(0));
    217   }
    218 
    219   @Test
    220   @SandboxConfig(shadows = {ShadowNonInstrumentedClass.class})
    221   public void shouldInstrumentClassIfAddedToConfig() {
    222     assertEquals(2, new NonInstrumentedClass().plus(0));
    223   }
    224 
    225   public static class NonInstrumentedClass {
    226     public int plus(int x) {
    227       return x + 1;
    228     }
    229   }
    230 
    231   @Implements(NonInstrumentedClass.class)
    232   public static class ShadowNonInstrumentedClass {
    233     @Implementation
    234     protected int plus(int x) {
    235       return x + 2;
    236     }
    237   }
    238 
    239   @Test
    240   public void shouldNotInstrumentPackageIfNotAddedToConfig() throws Exception {
    241     Class<?> clazz = Class.forName(AnUninstrumentedClass.class.getName());
    242     assertTrue(Modifier.isFinal(clazz.getModifiers()));
    243   }
    244 
    245   @Test
    246   @SandboxConfig(instrumentedPackages = {"org.robolectric.testing"})
    247   public void shouldInstrumentPackageIfAddedToConfig() throws Exception {
    248     Class<?> clazz = Class.forName(AnUninstrumentedClass.class.getName());
    249     assertFalse(Modifier.isFinal(clazz.getModifiers()));
    250   }
    251 }
    252