Home | History | Annotate | Download | only in robolectric
      1 package com.xtremelabs.robolectric;
      2 
      3 import com.xtremelabs.robolectric.RobolectricTestRunner.InstrumentDetector;
      4 import com.xtremelabs.robolectric.bytecode.ClassHandler;
      5 import com.xtremelabs.robolectric.bytecode.RobolectricClassLoader;
      6 import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
      7 import org.junit.Test;
      8 import org.junit.runner.JUnitCore;
      9 import org.junit.runner.Result;
     10 import org.junit.runner.RunWith;
     11 import org.junit.runners.model.InitializationError;
     12 
     13 import java.io.PrintWriter;
     14 import java.io.StringWriter;
     15 
     16 import static com.xtremelabs.robolectric.util.TestUtil.resourceFile;
     17 import static org.hamcrest.CoreMatchers.equalTo;
     18 import static org.junit.Assert.assertThat;
     19 import static org.junit.Assert.assertTrue;
     20 
     21 /**
     22  * Tests related to custom instrument detection strategy
     23  * that is used for introducing custom class loaders to test runners.
     24  */
     25 public class InstrumentDetectorTest {
     26 
     27     // ==================== CLASSLOADER ====================
     28 
     29     /** Custom class loader. It must be singleton. */
     30     public static class ClassLoaderForTesting extends RobolectricClassLoader {
     31 
     32         /** Instance. */
     33         private static ClassLoaderForTesting instance;
     34 
     35         /** Usage flag. */
     36         static boolean usageFlag = false;
     37 
     38         public static ClassLoaderForTesting getInstance() {
     39             if (instance == null) {
     40                 instance = new ClassLoaderForTesting(ShadowWrangler.getInstance());
     41             }
     42             return instance;
     43         }
     44 
     45         protected ClassLoaderForTesting(final ClassHandler classHandler) {
     46             super(classHandler);
     47         }
     48 
     49         @Override
     50         public Class<?> loadClass(final String name) throws ClassNotFoundException {
     51             if (!usageFlag) {
     52                 System.setProperty("robolectric.cusomClassLoader", "yes");
     53             }
     54             usageFlag = true;
     55             return super.loadClass(name);
     56         }
     57 
     58     }
     59 
     60     // ==================== RUNNERS ====================
     61 
     62     /** Custom runner that uses custom class loader but does not modify instrument detection.  */
     63     public static class RunnerForTesting extends RobolectricTestRunner {
     64 
     65         public RunnerForTesting(final Class<?> testClass) throws InitializationError {
     66             super(
     67                     testClass,
     68                     isInstrumented() ? null : ShadowWrangler.getInstance(),
     69                     isInstrumented() ? null : ClassLoaderForTesting.getInstance(),
     70                     new RobolectricConfig(resourceFile("TestAndroidManifest.xml"), resourceFile("res"), resourceFile("assets"))
     71                   );
     72         }
     73 
     74     }
     75 
     76     /** Custom runner that uses custom class loader.  */
     77     public static class RunnerForTestingThatWillPass extends RobolectricTestRunner {
     78 
     79         static {
     80             RunnerForTestingThatWillPass.setInstrumentDetector(CUSTOM_DETECTOR);
     81         }
     82 
     83         public RunnerForTestingThatWillPass(final Class<?> testClass) throws InitializationError {
     84             super(
     85                     testClass,
     86                     isInstrumented() ? null : ShadowWrangler.getInstance(),
     87                     isInstrumented() ? null : ClassLoaderForTesting.getInstance(),
     88                     new RobolectricConfig(resourceFile("TestAndroidManifest.xml"), resourceFile("res"), resourceFile("assets"))
     89                   );
     90         }
     91 
     92     }
     93 
     94     /** Custom instrument detector. */
     95     private static final InstrumentDetector CUSTOM_DETECTOR = new InstrumentDetector() {
     96         @Override
     97         public boolean isInstrumented() {
     98             final String currentLoader = RunnerForTestingThatWillPass.class.getClassLoader().getClass().getName();
     99             return currentLoader.contains(ClassLoaderForTesting.class.getName());
    100         }
    101     };
    102 
    103 
    104     // ==================== TEST CLASSES ====================
    105 
    106     /**
    107      * Default behavior test.
    108      */
    109     public static class DefaultBehaviorTest {
    110         @Test
    111         public void fakeTest() {
    112             assertThat(true, equalTo(true));
    113         }
    114     }
    115 
    116     /**
    117      * Test that is launched with a custom test runner and will fail.
    118      */
    119     @RunWith(RunnerForTesting.class)
    120     public static class TestWithCustomRunner {
    121         @Test
    122         public void loadedWithCustomClassLoader_usageFlagShoudBeTrue() {
    123             assertThat(System.getProperty("robolectric.cusomClassLoader"), equalTo("yes"));
    124         }
    125     }
    126 
    127     /**
    128      * Test that is launched with a custom test runner and will pass.
    129      */
    130     @RunWith(RunnerForTestingThatWillPass.class)
    131     public static class TestWithCustomRunnerThatWillPass extends TestWithCustomRunner {
    132         // nothing here, we just need another annotation
    133     }
    134 
    135 
    136     // ==================== RUN METHODS ====================
    137 
    138     /**
    139      * This is default behavior.
    140      */
    141     @Test
    142     public void withDefaultDetectorAndDefaultRunner_shouldPass() {
    143         final Result result =  JUnitCore.runClasses(DefaultBehaviorTest.class);
    144         assertThat(result.getRunCount(), equalTo(1));
    145         assertThat(result.getFailureCount(), equalTo(0));
    146     }
    147 
    148     /**
    149      * This test simulates wrong instrument detection when custom class loader is used.
    150      */
    151     @Test
    152     public void wrongInstrumentDetection_shouldRaiseLinkageError() {
    153         final Result result =  JUnitCore.runClasses(TestWithCustomRunner.class);
    154         assertThat(result.getRunCount(), equalTo(1));
    155         assertThat(result.getFailureCount(), equalTo(1));
    156 
    157         // check whether it's a linkage error
    158         final StringWriter buffer = new StringWriter();
    159         result.getFailures().get(0).getException().printStackTrace(new PrintWriter(buffer));
    160         final int linkageErrorNameIndex = buffer.toString().indexOf(LinkageError.class.getName());
    161         assertTrue(linkageErrorNameIndex >= 0);
    162     }
    163 
    164     /**
    165      * Propper behavior test.
    166      */
    167     @Test
    168     public void customizeInstumentDetection_shouldPass() {
    169         final Result result =  JUnitCore.runClasses(TestWithCustomRunnerThatWillPass.class);
    170         assertThat(result.getRunCount(), equalTo(1));
    171         assertThat(result.getFailureCount(), equalTo(0));
    172     }
    173 
    174 }
    175