1 package com.xtremelabs.robolectric.bytecode;
2 
3 import com.xtremelabs.robolectric.Robolectric;
4 import com.xtremelabs.robolectric.WithoutTestDefaultsRunner;
5 import com.xtremelabs.robolectric.annotation.EnableStrictI18n;
6 import com.xtremelabs.robolectric.internal.Implementation;
7 import com.xtremelabs.robolectric.internal.Implements;
8 import com.xtremelabs.robolectric.internal.Instrument;
9 import com.xtremelabs.robolectric.internal.RealObject;
10 import org.junit.Before;
11 import org.junit.Ignore;
12 import org.junit.Test;
13 import org.junit.runner.RunWith;
14 
15 import java.io.IOException;
16 import java.io.PrintWriter;
17 import java.io.StringWriter;
18 
19 import static org.hamcrest.CoreMatchers.instanceOf;
20 import static org.hamcrest.CoreMatchers.not;
21 import static org.hamcrest.core.StringContains.containsString;
22 import static org.junit.Assert.*;
23 
24 @RunWith(WithoutTestDefaultsRunner.class)
25 public class ShadowWranglerTest {
26     private String name;
27 
28     @Before
setUp()29     public void setUp() throws Exception {
30         name = "context";
31     }
32 
33     @Test
testConstructorInvocation_WithDefaultConstructorAndNoConstructorDelegateOnShadowClass()34     public void testConstructorInvocation_WithDefaultConstructorAndNoConstructorDelegateOnShadowClass() throws Exception {
35         Robolectric.bindShadowClass(ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate.class);
36 
37         Foo foo = new Foo(name);
38         assertEquals(ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate.class, Robolectric.shadowOf_(foo).getClass());
39     }
40 
41     @Test
testConstructorInvocation()42     public void testConstructorInvocation() throws Exception {
43         Robolectric.bindShadowClass(ShadowFoo.class);
44 
45         Foo foo = new Foo(name);
46         assertSame(name, shadowOf(foo).name);
47         assertSame(foo, shadowOf(foo).realFooCtor);
48     }
49 
50     @Test
testRealObjectAnnotatedFieldsAreSetBeforeConstructorIsCalled()51     public void testRealObjectAnnotatedFieldsAreSetBeforeConstructorIsCalled() throws Exception {
52         Robolectric.bindShadowClass(ShadowFoo.class);
53 
54         Foo foo = new Foo(name);
55         assertSame(name, shadowOf(foo).name);
56         assertSame(foo, shadowOf(foo).realFooField);
57 
58         assertSame(foo, shadowOf(foo).realFooInConstructor);
59         assertSame(foo, shadowOf(foo).realFooInParentConstructor);
60     }
61 
62     @Test
testMethodDelegation()63     public void testMethodDelegation() throws Exception {
64         Robolectric.bindShadowClass(ShadowFoo.class);
65 
66         Foo foo = new Foo(name);
67         assertSame(name, foo.getName());
68     }
69 
70     @Test
testEqualsMethodDelegation()71     public void testEqualsMethodDelegation() throws Exception {
72         Robolectric.bindShadowClass(WithEquals.class);
73 
74         Foo foo1 = new Foo(name);
75         Foo foo2 = new Foo(name);
76         assertEquals(foo1, foo2);
77     }
78 
79     @Test
testHashCodeMethodDelegation()80     public void testHashCodeMethodDelegation() throws Exception {
81         Robolectric.bindShadowClass(WithEquals.class);
82 
83         Foo foo = new Foo(name);
84         assertEquals(42, foo.hashCode());
85     }
86 
87     @Test
testToStringMethodDelegation()88     public void testToStringMethodDelegation() throws Exception {
89         Robolectric.bindShadowClass(WithToString.class);
90 
91         Foo foo = new Foo(name);
92         assertEquals("the expected string", foo.toString());
93     }
94 
95     @Test
testShadowSelectionSearchesSuperclasses()96     public void testShadowSelectionSearchesSuperclasses() throws Exception {
97         Robolectric.bindShadowClass(ShadowFoo.class);
98 
99         TextFoo textFoo = new TextFoo(name);
100         assertEquals(ShadowFoo.class, Robolectric.shadowOf_(textFoo).getClass());
101     }
102 
103     @Test
shouldUseMostSpecificShadow()104     public void shouldUseMostSpecificShadow() throws Exception {
105         Robolectric.bindShadowClass(ShadowFoo.class);
106         Robolectric.bindShadowClass(ShadowTextFoo.class);
107 
108         TextFoo textFoo = new TextFoo(name);
109         assertThat(shadowOf(textFoo), instanceOf(ShadowTextFoo.class));
110     }
111 
112     @Test
testPrimitiveArrays()113     public void testPrimitiveArrays() throws Exception {
114         Class<?> objArrayClass = ShadowWrangler.loadClass("java.lang.Object[]", getClass().getClassLoader());
115         assertTrue(objArrayClass.isArray());
116         assertEquals(Object.class, objArrayClass.getComponentType());
117 
118         Class<?> intArrayClass = ShadowWrangler.loadClass("int[]", getClass().getClassLoader());
119         assertTrue(intArrayClass.isArray());
120         assertEquals(Integer.TYPE, intArrayClass.getComponentType());
121     }
122 
123     @Test
shouldRemoveNoiseFromStackTraces()124     public void shouldRemoveNoiseFromStackTraces() throws Exception {
125         Robolectric.bindShadowClass(ExceptionThrowingShadowFoo.class);
126         Foo foo = new Foo(null);
127 
128         Exception e = null;
129         try {
130             foo.getName();
131         } catch (Exception e1) {
132             e = e1;
133         }
134 
135         assertNotNull(e);
136         assertEquals(IOException.class, e.getClass());
137         assertEquals("fake exception", e.getMessage());
138         StringWriter stringWriter = new StringWriter();
139         e.printStackTrace(new PrintWriter(stringWriter));
140         String stackTrace = stringWriter.getBuffer().toString();
141 
142         assertThat(stackTrace, containsString("fake exception"));
143         assertThat(stackTrace, containsString(ExceptionThrowingShadowFoo.class.getName() + ".getName("));
144         assertThat(stackTrace, containsString(Foo.class.getName() + ".getName("));
145         assertThat(stackTrace, containsString(ShadowWranglerTest.class.getName() + ".shouldRemoveNoiseFromStackTraces"));
146 
147         assertThat(stackTrace, not(containsString("sun.reflect")));
148         assertThat(stackTrace, not(containsString("java.lang.reflect")));
149         assertThat(stackTrace, not(containsString(ShadowWrangler.class.getName() + ".")));
150         assertThat(stackTrace, not(containsString(RobolectricInternals.class.getName() + ".")));
151     }
152 
153     @Test(expected=RuntimeException.class)
154     @EnableStrictI18n
shouldThrowExceptionOnI18nStrictMode()155     public void shouldThrowExceptionOnI18nStrictMode() {
156     	Robolectric.bindShadowClass(ShadowFooI18n.class);
157     	Foo foo = new Foo(null);
158     	foo.getName();
159     }
160 
shadowOf(Foo foo)161     private ShadowFoo shadowOf(Foo foo) {
162         return (ShadowFoo) Robolectric.shadowOf_(foo);
163     }
164 
shadowOf(TextFoo foo)165     private ShadowTextFoo shadowOf(TextFoo foo) {
166         return (ShadowTextFoo) Robolectric.shadowOf_(foo);
167     }
168 
169     @Implements(Foo.class)
170     public static class WithEquals {
171         @Override
equals(Object o)172         public boolean equals(Object o) {
173             return true;
174         }
175 
176 
177         @Override
hashCode()178         public int hashCode() {
179             return 42;
180         }
181 
182     }
183 
184     @Implements(Foo.class)
185     public static class WithToString {
186         @Override
toString()187         public String toString() {
188             return "the expected string";
189         }
190     }
191 
192     @Implements(TextFoo.class)
193     public static class ShadowTextFoo {
194     }
195 
196     @Instrument
197     public static class TextFoo extends Foo {
TextFoo(String s)198         public TextFoo(String s) {
199             super(s);
200         }
201     }
202 
203     @Implements(Foo.class)
204     public static class ShadowFooI18n {
205     	String name;
206 
__constructor__(String name)207         public void __constructor__(String name) {
208            this.name = name;
209         }
210 
211     	@Implementation(i18nSafe=false)
getName()212     	public String getName() {
213     		return name;
214     	}
215     }
216 
217     @Implements(Foo.class)
218     public static class ShadowFooParent {
219         @RealObject
220         private Foo realFoo;
221         Foo realFooInParentConstructor;
222 
__constructor__(String name)223         public void __constructor__(String name) {
224             realFooInParentConstructor = realFoo;
225         }
226     }
227 
228     @Implements(Foo.class)
229     public static class ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate {
230     }
231 
232     @Implements(Foo.class)
233     public static class ExceptionThrowingShadowFoo {
234         @SuppressWarnings({"UnusedDeclaration"})
getName()235         public String getName() throws IOException {
236             throw new IOException("fake exception");
237         }
238     }
239 }
240