| package com.xtremelabs.robolectric.bytecode; |
| |
| import com.xtremelabs.robolectric.Robolectric; |
| import com.xtremelabs.robolectric.WithoutTestDefaultsRunner; |
| import com.xtremelabs.robolectric.annotation.EnableStrictI18n; |
| import com.xtremelabs.robolectric.internal.Implementation; |
| import com.xtremelabs.robolectric.internal.Implements; |
| import com.xtremelabs.robolectric.internal.Instrument; |
| import com.xtremelabs.robolectric.internal.RealObject; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| |
| import static org.hamcrest.CoreMatchers.instanceOf; |
| import static org.hamcrest.CoreMatchers.not; |
| import static org.hamcrest.core.StringContains.containsString; |
| import static org.junit.Assert.*; |
| |
| @RunWith(WithoutTestDefaultsRunner.class) |
| public class ShadowWranglerTest { |
| private String name; |
| |
| @Before |
| public void setUp() throws Exception { |
| name = "context"; |
| } |
| |
| @Test |
| public void testConstructorInvocation_WithDefaultConstructorAndNoConstructorDelegateOnShadowClass() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate.class); |
| |
| Foo foo = new Foo(name); |
| assertEquals(ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate.class, Robolectric.shadowOf_(foo).getClass()); |
| } |
| |
| @Test |
| public void testConstructorInvocation() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo.class); |
| |
| Foo foo = new Foo(name); |
| assertSame(name, shadowOf(foo).name); |
| assertSame(foo, shadowOf(foo).realFooCtor); |
| } |
| |
| @Test |
| public void testRealObjectAnnotatedFieldsAreSetBeforeConstructorIsCalled() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo.class); |
| |
| Foo foo = new Foo(name); |
| assertSame(name, shadowOf(foo).name); |
| assertSame(foo, shadowOf(foo).realFooField); |
| |
| assertSame(foo, shadowOf(foo).realFooInConstructor); |
| assertSame(foo, shadowOf(foo).realFooInParentConstructor); |
| } |
| |
| @Test |
| public void testMethodDelegation() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo.class); |
| |
| Foo foo = new Foo(name); |
| assertSame(name, foo.getName()); |
| } |
| |
| @Test |
| public void testEqualsMethodDelegation() throws Exception { |
| Robolectric.bindShadowClass(WithEquals.class); |
| |
| Foo foo1 = new Foo(name); |
| Foo foo2 = new Foo(name); |
| assertEquals(foo1, foo2); |
| } |
| |
| @Test |
| public void testHashCodeMethodDelegation() throws Exception { |
| Robolectric.bindShadowClass(WithEquals.class); |
| |
| Foo foo = new Foo(name); |
| assertEquals(42, foo.hashCode()); |
| } |
| |
| @Test |
| public void testToStringMethodDelegation() throws Exception { |
| Robolectric.bindShadowClass(WithToString.class); |
| |
| Foo foo = new Foo(name); |
| assertEquals("the expected string", foo.toString()); |
| } |
| |
| @Test |
| public void testShadowSelectionSearchesSuperclasses() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo.class); |
| |
| TextFoo textFoo = new TextFoo(name); |
| assertEquals(ShadowFoo.class, Robolectric.shadowOf_(textFoo).getClass()); |
| } |
| |
| @Test |
| public void shouldUseMostSpecificShadow() throws Exception { |
| Robolectric.bindShadowClass(ShadowFoo.class); |
| Robolectric.bindShadowClass(ShadowTextFoo.class); |
| |
| TextFoo textFoo = new TextFoo(name); |
| assertThat(shadowOf(textFoo), instanceOf(ShadowTextFoo.class)); |
| } |
| |
| @Test |
| public void testPrimitiveArrays() throws Exception { |
| Class<?> objArrayClass = ShadowWrangler.loadClass("java.lang.Object[]", getClass().getClassLoader()); |
| assertTrue(objArrayClass.isArray()); |
| assertEquals(Object.class, objArrayClass.getComponentType()); |
| |
| Class<?> intArrayClass = ShadowWrangler.loadClass("int[]", getClass().getClassLoader()); |
| assertTrue(intArrayClass.isArray()); |
| assertEquals(Integer.TYPE, intArrayClass.getComponentType()); |
| } |
| |
| @Test |
| public void shouldRemoveNoiseFromStackTraces() throws Exception { |
| Robolectric.bindShadowClass(ExceptionThrowingShadowFoo.class); |
| Foo foo = new Foo(null); |
| |
| Exception e = null; |
| try { |
| foo.getName(); |
| } catch (Exception e1) { |
| e = e1; |
| } |
| |
| assertNotNull(e); |
| assertEquals(IOException.class, e.getClass()); |
| assertEquals("fake exception", e.getMessage()); |
| StringWriter stringWriter = new StringWriter(); |
| e.printStackTrace(new PrintWriter(stringWriter)); |
| String stackTrace = stringWriter.getBuffer().toString(); |
| |
| assertThat(stackTrace, containsString("fake exception")); |
| assertThat(stackTrace, containsString(ExceptionThrowingShadowFoo.class.getName() + ".getName(")); |
| assertThat(stackTrace, containsString(Foo.class.getName() + ".getName(")); |
| assertThat(stackTrace, containsString(ShadowWranglerTest.class.getName() + ".shouldRemoveNoiseFromStackTraces")); |
| |
| assertThat(stackTrace, not(containsString("sun.reflect"))); |
| assertThat(stackTrace, not(containsString("java.lang.reflect"))); |
| assertThat(stackTrace, not(containsString(ShadowWrangler.class.getName() + "."))); |
| assertThat(stackTrace, not(containsString(RobolectricInternals.class.getName() + "."))); |
| } |
| |
| @Test(expected=RuntimeException.class) |
| @EnableStrictI18n |
| public void shouldThrowExceptionOnI18nStrictMode() { |
| Robolectric.bindShadowClass(ShadowFooI18n.class); |
| Foo foo = new Foo(null); |
| foo.getName(); |
| } |
| |
| private ShadowFoo shadowOf(Foo foo) { |
| return (ShadowFoo) Robolectric.shadowOf_(foo); |
| } |
| |
| private ShadowTextFoo shadowOf(TextFoo foo) { |
| return (ShadowTextFoo) Robolectric.shadowOf_(foo); |
| } |
| |
| @Implements(Foo.class) |
| public static class WithEquals { |
| @Override |
| public boolean equals(Object o) { |
| return true; |
| } |
| |
| |
| @Override |
| public int hashCode() { |
| return 42; |
| } |
| |
| } |
| |
| @Implements(Foo.class) |
| public static class WithToString { |
| @Override |
| public String toString() { |
| return "the expected string"; |
| } |
| } |
| |
| @Implements(TextFoo.class) |
| public static class ShadowTextFoo { |
| } |
| |
| @Instrument |
| public static class TextFoo extends Foo { |
| public TextFoo(String s) { |
| super(s); |
| } |
| } |
| |
| @Implements(Foo.class) |
| public static class ShadowFooI18n { |
| String name; |
| |
| public void __constructor__(String name) { |
| this.name = name; |
| } |
| |
| @Implementation(i18nSafe=false) |
| public String getName() { |
| return name; |
| } |
| } |
| |
| @Implements(Foo.class) |
| public static class ShadowFooParent { |
| @RealObject |
| private Foo realFoo; |
| Foo realFooInParentConstructor; |
| |
| public void __constructor__(String name) { |
| realFooInParentConstructor = realFoo; |
| } |
| } |
| |
| @Implements(Foo.class) |
| public static class ShadowFoo_WithDefaultConstructorAndNoConstructorDelegate { |
| } |
| |
| @Implements(Foo.class) |
| public static class ExceptionThrowingShadowFoo { |
| @SuppressWarnings({"UnusedDeclaration"}) |
| public String getName() throws IOException { |
| throw new IOException("fake exception"); |
| } |
| } |
| } |