package org.elixir_lang.mix.runner.exunit; import com.intellij.execution.DefaultExecutionResult; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil; import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties; import com.intellij.execution.ui.ConsoleView; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; import org.elixir_lang.console.ElixirConsoleUtil; import org.elixir_lang.exunit.ElixirModules; import org.elixir_lang.mix.runner.MixRunningState; import org.elixir_lang.mix.settings.MixSettings; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; final class MixExUnitRunningState extends MixRunningState { private static final Logger LOGGER = com.intellij.openapi.diagnostic.Logger.getInstance(MixExUnitRunningState.class); private final String TEST_FRAMEWORK_NAME = "ExUnit"; MixExUnitRunningState(@NotNull ExecutionEnvironment environment, MixExUnitRunConfiguration configuration) { super(environment, configuration); } @NotNull @Override public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { ProcessHandler processHandler = startProcess(); TestConsoleProperties properties = new SMTRunnerConsoleProperties(myConfiguration, TEST_FRAMEWORK_NAME, executor); ConsoleView console = createAndAttachConsole(TEST_FRAMEWORK_NAME, processHandler, properties); ElixirConsoleUtil.attachFilters(myConfiguration.getProject(), console); return new DefaultExecutionResult(console, processHandler, createActions(console, processHandler)); } @NotNull public ConsoleView createConsoleView(Executor executor) { TestConsoleProperties properties = new SMTRunnerConsoleProperties(myConfiguration, TEST_FRAMEWORK_NAME, executor); return createConsole(TEST_FRAMEWORK_NAME, properties); } /** * Unifies the interface for {@code SMTestRunnerConnectionUtil.createConsole} between 141 and later releases */ private ConsoleView createConsole(@NotNull String name , @NotNull TestConsoleProperties testConsoleProperties) { ConsoleView consoleView = null; try { Method createConsole2 = SMTestRunnerConnectionUtil.class.getMethod( "createConsole", String.class, TestConsoleProperties.class ); try { // first argument is `null` because it's a static method consoleView = (ConsoleView) createConsole2.invoke(null, name, testConsoleProperties); } catch (IllegalAccessException | InvocationTargetException e) { LOGGER.error(e); } } catch (NoSuchMethodException e) { try { Method createConsole3 = SMTestRunnerConnectionUtil.class.getMethod( "createConsole", String.class, TestConsoleProperties.class, ExecutionEnvironment.class ); try { // first argument is `null` because it's a static method consoleView = (ConsoleView) createConsole3.invoke(null, name, testConsoleProperties, null); } catch (IllegalAccessException | InvocationTargetException e1) { LOGGER.error(e1); } } catch (NoSuchMethodException e1) { LOGGER.error(e1); } } //noinspection ConstantConditions return consoleView; } /** * Unifies the interface for {@code SMTestRunnerConnectionUtil.createAndAttachConsole} between 141 and later releases */ private ConsoleView createAndAttachConsole(@NotNull String testFrameworkName, @NotNull ProcessHandler processHandler, @NotNull TestConsoleProperties consoleProperties) throws ExecutionException { Class<SMTestRunnerConnectionUtil> klass = SMTestRunnerConnectionUtil.class; ConsoleView consoleView = null; try { Method createAndAttachConsole = klass.getMethod("createAndAttachConsole", String.class, ProcessHandler.class, TestConsoleProperties.class); try { consoleView = (ConsoleView) createAndAttachConsole.invoke(null, testFrameworkName, processHandler, consoleProperties); } catch (IllegalAccessException | InvocationTargetException e) { LOGGER.error(e); } } catch (NoSuchMethodException noSuchCreateAndAttachConsole3Method) { try { Method createAndAttachConsole = klass.getMethod("createAndAttachConsole", String.class, ProcessHandler.class, TestConsoleProperties.class, ExecutionEnvironment.class); try { consoleView = (ConsoleView) createAndAttachConsole.invoke(null, testFrameworkName, processHandler, consoleProperties, getEnvironment()); } catch (IllegalAccessException | InvocationTargetException e) { LOGGER.error(e); } } catch (NoSuchMethodException noSuchCreateAndAttachConsole4Method) { noSuchCreateAndAttachConsole4Method.printStackTrace(); } } return consoleView; } private static File createElixirModulesDirectory() throws IOException { return FileUtil.createTempDirectory("intellij_elixir_modules", null); } private boolean useCustomMixTask() { return !MixSettings.getInstance(myConfiguration.getProject()).getSupportsFormatterOption(); } @NotNull private static List<String> elixirParams(@NotNull Collection<File> elixirModuleFileCollection) { ArrayList<String> elixirParams = new ArrayList<>(); for (File elixirModuleFile : elixirModuleFileCollection) { elixirParams.add("-r"); elixirParams.add(String.valueOf(elixirModuleFile)); } return elixirParams; } @NotNull public List<String> setupElixirParams() throws ExecutionException { List<File> elixirModuleFileList = new ArrayList<>(); try { File elixirModulesDir = createElixirModulesDirectory(); elixirModuleFileList.add(ElixirModules.putFormatterTo(elixirModulesDir)); // Support for the --formatter option was recently added to Mix. Older versions of Elixir will need to use the // custom task we've included in order to support this option if (useCustomMixTask()) { elixirModuleFileList.add(ElixirModules.putMixTaskTo(elixirModulesDir)); } } catch(IOException e) { throw new ExecutionException(e); } return elixirParams(elixirModuleFileList); } }