Home | History | Annotate | Download | only in bytecode
      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
     29     public void setUp() throws Exception {
     30         name = "context";
     31     }
     32 
     33     @Test
     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
     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
     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
     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
     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
     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
     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
     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
    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
    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
    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
    155     public void shouldThrowExceptionOnI18nStrictMode() {
    156     	Robolectric.bindShadowClass(ShadowFooI18n.class);
    157     	Foo foo = new Foo(null);
    158     	foo.getName();
    159     }
    160 
    161     private ShadowFoo shadowOf(Foo foo) {
    162         return (ShadowFoo) Robolectric.shadowOf_(foo);
    163     }
    164 
    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
    172         public boolean equals(Object o) {
    173             return true;
    174         }
    175 
    176 
    177         @Override
    178         public int hashCode() {
    179             return 42;
    180         }
    181 
    182     }
    183 
    184     @Implements(Foo.class)
    185     public static class WithToString {
    186         @Override
    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 {
    198         public TextFoo(String s) {
    199             super(s);
    200         }
    201     }
    202 
    203     @Implements(Foo.class)
    204     public static class ShadowFooI18n {
    205     	String name;
    206 
    207         public void __constructor__(String name) {
    208            this.name = name;
    209         }
    210 
    211     	@Implementation(i18nSafe=false)
    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 
    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"})
    235         public String getName() throws IOException {
    236             throw new IOException("fake exception");
    237         }
    238     }
    239 }
    240