blob: 01127889729c3e043c557b467ae2fbeb8a70d28e [file] [log] [blame]
package com.xtremelabs.robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner.InstrumentDetector;
import com.xtremelabs.robolectric.bytecode.ClassHandler;
import com.xtremelabs.robolectric.bytecode.RobolectricClassLoader;
import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runners.model.InitializationError;
import java.io.PrintWriter;
import java.io.StringWriter;
import static com.xtremelabs.robolectric.util.TestUtil.resourceFile;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests related to custom instrument detection strategy
* that is used for introducing custom class loaders to test runners.
*/
public class InstrumentDetectorTest {
// ==================== CLASSLOADER ====================
/** Custom class loader. It must be singleton. */
public static class ClassLoaderForTesting extends RobolectricClassLoader {
/** Instance. */
private static ClassLoaderForTesting instance;
/** Usage flag. */
static boolean usageFlag = false;
public static ClassLoaderForTesting getInstance() {
if (instance == null) {
instance = new ClassLoaderForTesting(ShadowWrangler.getInstance());
}
return instance;
}
protected ClassLoaderForTesting(final ClassHandler classHandler) {
super(classHandler);
}
@Override
public Class<?> loadClass(final String name) throws ClassNotFoundException {
if (!usageFlag) {
System.setProperty("robolectric.cusomClassLoader", "yes");
}
usageFlag = true;
return super.loadClass(name);
}
}
// ==================== RUNNERS ====================
/** Custom runner that uses custom class loader but does not modify instrument detection. */
public static class RunnerForTesting extends RobolectricTestRunner {
public RunnerForTesting(final Class<?> testClass) throws InitializationError {
super(
testClass,
isInstrumented() ? null : ShadowWrangler.getInstance(),
isInstrumented() ? null : ClassLoaderForTesting.getInstance(),
new RobolectricConfig(resourceFile("TestAndroidManifest.xml"), resourceFile("res"), resourceFile("assets"))
);
}
}
/** Custom runner that uses custom class loader. */
public static class RunnerForTestingThatWillPass extends RobolectricTestRunner {
static {
RunnerForTestingThatWillPass.setInstrumentDetector(CUSTOM_DETECTOR);
}
public RunnerForTestingThatWillPass(final Class<?> testClass) throws InitializationError {
super(
testClass,
isInstrumented() ? null : ShadowWrangler.getInstance(),
isInstrumented() ? null : ClassLoaderForTesting.getInstance(),
new RobolectricConfig(resourceFile("TestAndroidManifest.xml"), resourceFile("res"), resourceFile("assets"))
);
}
}
/** Custom instrument detector. */
private static final InstrumentDetector CUSTOM_DETECTOR = new InstrumentDetector() {
@Override
public boolean isInstrumented() {
final String currentLoader = RunnerForTestingThatWillPass.class.getClassLoader().getClass().getName();
return currentLoader.contains(ClassLoaderForTesting.class.getName());
}
};
// ==================== TEST CLASSES ====================
/**
* Default behavior test.
*/
public static class DefaultBehaviorTest {
@Test
public void fakeTest() {
assertThat(true, equalTo(true));
}
}
/**
* Test that is launched with a custom test runner and will fail.
*/
@RunWith(RunnerForTesting.class)
public static class TestWithCustomRunner {
@Test
public void loadedWithCustomClassLoader_usageFlagShoudBeTrue() {
assertThat(System.getProperty("robolectric.cusomClassLoader"), equalTo("yes"));
}
}
/**
* Test that is launched with a custom test runner and will pass.
*/
@RunWith(RunnerForTestingThatWillPass.class)
public static class TestWithCustomRunnerThatWillPass extends TestWithCustomRunner {
// nothing here, we just need another annotation
}
// ==================== RUN METHODS ====================
/**
* This is default behavior.
*/
@Test
public void withDefaultDetectorAndDefaultRunner_shouldPass() {
final Result result = JUnitCore.runClasses(DefaultBehaviorTest.class);
assertThat(result.getRunCount(), equalTo(1));
assertThat(result.getFailureCount(), equalTo(0));
}
/**
* This test simulates wrong instrument detection when custom class loader is used.
*/
@Test
public void wrongInstrumentDetection_shouldRaiseLinkageError() {
final Result result = JUnitCore.runClasses(TestWithCustomRunner.class);
assertThat(result.getRunCount(), equalTo(1));
assertThat(result.getFailureCount(), equalTo(1));
// check whether it's a linkage error
final StringWriter buffer = new StringWriter();
result.getFailures().get(0).getException().printStackTrace(new PrintWriter(buffer));
final int linkageErrorNameIndex = buffer.toString().indexOf(LinkageError.class.getName());
assertTrue(linkageErrorNameIndex >= 0);
}
/**
* Propper behavior test.
*/
@Test
public void customizeInstumentDetection_shouldPass() {
final Result result = JUnitCore.runClasses(TestWithCustomRunnerThatWillPass.class);
assertThat(result.getRunCount(), equalTo(1));
assertThat(result.getFailureCount(), equalTo(0));
}
}