1 package org.robolectric; 2 3 import static com.google.common.truth.Truth.assertThat; 4 5 import java.lang.reflect.Field; 6 import org.junit.Test; 7 import org.junit.runner.RunWith; 8 import org.robolectric.annotation.Implementation; 9 import org.robolectric.annotation.Implements; 10 import org.robolectric.annotation.RealObject; 11 import org.robolectric.annotation.internal.Instrument; 12 import org.robolectric.internal.SandboxTestRunner; 13 import org.robolectric.internal.bytecode.SandboxConfig; 14 import org.robolectric.shadow.api.Shadow; 15 16 @RunWith(SandboxTestRunner.class) 17 public class ThreadSafetyTest { 18 @Test 19 @SandboxConfig(shadows = {InstrumentedThreadShadow.class}) shadowCreationShouldBeThreadsafe()20 public void shadowCreationShouldBeThreadsafe() throws Exception { 21 Field field = InstrumentedThread.class.getDeclaredField("shadowFromOtherThread"); 22 field.setAccessible(true); 23 24 for (int i = 0; i < 100; i++) { // :-( 25 InstrumentedThread instrumentedThread = new InstrumentedThread(); 26 instrumentedThread.start(); 27 Object shadowFromThisThread = Shadow.extract(instrumentedThread); 28 29 instrumentedThread.join(); 30 Object shadowFromOtherThread = field.get(instrumentedThread); 31 assertThat(shadowFromThisThread).isSameInstanceAs(shadowFromOtherThread); 32 } 33 } 34 35 @Instrument 36 public static class InstrumentedThread extends Thread { 37 InstrumentedThreadShadow shadowFromOtherThread; 38 39 @Override run()40 public void run() { 41 shadowFromOtherThread = Shadow.extract(this); 42 } 43 } 44 45 @Implements(InstrumentedThread.class) 46 public static class InstrumentedThreadShadow { 47 @RealObject InstrumentedThread realObject; 48 @Implementation run()49 protected void run() { 50 Shadow.directlyOn(realObject, InstrumentedThread.class, "run"); 51 } 52 } 53 } 54