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