package jetbrains.mps.testbench.junit.runners; /*Generated by MPS */ import java.util.List; import org.junit.runner.Runner; import java.util.ArrayList; import org.junit.runners.model.RunnerBuilder; import org.junit.runners.model.InitializationError; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; import jetbrains.mps.tool.environment.Environment; import jetbrains.mps.tool.environment.IdeaEnvironment; import org.jetbrains.mps.openapi.module.SModule; import jetbrains.mps.smodel.ModuleRepositoryFacade; import org.jetbrains.mps.openapi.persistence.PersistenceFacade; import jetbrains.mps.tool.environment.EnvironmentConfig; import jetbrains.mps.module.ReloadableModule; import org.junit.runner.notification.Failure; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.annotation.ElementType; public class ModuleSymbolicSuite extends BaseMpsRunner { private static final String NO_TESTS = "EMPTY TEST CASE"; private List<Runner> myRunners = new ArrayList<Runner>(); private String myModuleRef; private RunnerBuilder myBuilder; private boolean initialized = false; public ModuleSymbolicSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError { this(builder, klass); String[] tests = getAnnotatedTests(klass); String[] classes = getAnnotatedClassNames(klass); for (int i = 0; i < tests.length && i < classes.length; i++) { myRunners.add(new ModuleSymbolicSuite.DelegatingRunner(classes[i], (tests[i].length() > 0 ? tests[i].split(",") : null))); } this.myModuleRef = getAnnotatedModule(klass); } protected ModuleSymbolicSuite(RunnerBuilder builder, Class<?> klass) throws InitializationError { this(klass); this.myBuilder = builder; } protected ModuleSymbolicSuite(Class<?> klass) throws InitializationError { super(klass); } @Override protected List<Runner> getChildren() { return myRunners; } @Override protected Description describeChild(Runner child) { return child.getDescription(); } @Override protected void runChild(Runner child, RunNotifier notifier) { if (!(initialized)) { initialize(); } child.run(notifier); } private void initialize() { Environment env = IdeaEnvironment.getOrCreate(ModuleSymbolicSuite.createConfig()); env.createProject(new FromProjectPathProjectStrategy()); SModule mod = ModuleRepositoryFacade.getInstance().getModule(PersistenceFacade.getInstance().createModuleReference(myModuleRef)); for (Runner child : myRunners) { ((ModuleSymbolicSuite.DelegatingRunner) child).init(mod, myBuilder); } this.initialized = true; } private static String getAnnotatedModule(Class<?> klass) throws InitializationError { ModuleSymbolicSuite.ModuleReference mrefAnn = klass.getAnnotation(ModuleSymbolicSuite.ModuleReference.class); if (mrefAnn == null) { throw new InitializationError(String.format("class '%s' must have a ModuleReference annotation", klass.getName())); } return mrefAnn.value(); } private static String[] getAnnotatedClassNames(Class<?> klass) throws InitializationError { ModuleSymbolicSuite.ModuleClassSymbols symAnn = klass.getAnnotation(ModuleSymbolicSuite.ModuleClassSymbols.class); if (symAnn == null) { throw new InitializationError(String.format("class '%s' must have a ModuleClassSymbols annotation", klass.getName())); } return symAnn.classes(); } private static String[] getAnnotatedTests(Class<?> klass) throws InitializationError { ModuleSymbolicSuite.ModuleClassSymbols symAnn = klass.getAnnotation(ModuleSymbolicSuite.ModuleClassSymbols.class); if (symAnn == null) { throw new InitializationError(String.format("class '%s' must have a ModuleClassSymbols annotation", klass.getName())); } return symAnn.tests(); } private static EnvironmentConfig createConfig() { return EnvironmentConfig.defaultConfig().withBuildPlugin().withVcsPlugin(); } public static class DelegatingRunner extends Runner { private Runner myDelegate; private String myClassName; private String[] myTests; public DelegatingRunner(String klassName, String[] tests) { this.myClassName = klassName; this.myTests = tests; } @Override public void run(RunNotifier notifier) { if (myTests == null) { runFailure(createTestDescription(ModuleSymbolicSuite.NO_TESTS), new IllegalStateException("no tests found in " + myClassName), notifier); } else if (myDelegate == null) { for (String test : myTests) { runFailure(createTestDescription(test), new ClassNotFoundException(myClassName), notifier); } } else { myDelegate.run(notifier); } } @Override public Description getDescription() { Description desc = Description.createSuiteDescription(myClassName); if (myTests == null) { desc.addChild(createTestDescription(ModuleSymbolicSuite.NO_TESTS)); } else { for (String test : myTests) { desc.addChild(createTestDescription(test)); } } return desc; } private void init(SModule mod, RunnerBuilder builder) { if (mod instanceof ReloadableModule) { try { Class klass = ((ReloadableModule) mod).getClass(myClassName); if (klass != null) { this.myDelegate = builder.safeRunnerForClass(klass); } } catch (ClassNotFoundException ignored) { } } } private void runFailure(Description failDesc, Throwable cause, RunNotifier notifier) { notifier.fireTestStarted(failDesc); notifier.fireTestFailure(new Failure(failDesc, cause)); notifier.fireTestFinished(failDesc); } private Description createTestDescription(String text) { // this is the only way to construct Description from string return Description.createSuiteDescription(String.format("%s(%s)", text, myClassName)); } } @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) public @interface ModuleClassSymbols { String[] classes(); String[] tests(); } @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) public @interface ModuleReference { String value(); } }