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