/*
* Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.goide.runconfig.testing;
import com.goide.psi.GoFile;
import com.goide.psi.GoFunctionDeclaration;
import com.goide.runconfig.GoConsoleFilter;
import com.goide.runconfig.GoRunningState;
import com.goide.util.GoExecutor;
import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessTerminatedListener;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction;
import com.intellij.execution.testframework.autotest.ToggleAutoTestAction;
import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil;
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collection;
import java.util.List;
public class GoTestRunningState extends GoRunningState<GoTestRunConfiguration> {
private String myCoverageFilePath;
private String myFailedTestsPattern;
public GoTestRunningState(@NotNull ExecutionEnvironment env, @NotNull Module module, @NotNull GoTestRunConfiguration configuration) {
super(env, module, configuration);
}
@NotNull
@Override
public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
ProcessHandler processHandler = startProcess();
TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(myConfiguration.getProject());
setConsoleBuilder(consoleBuilder);
GoTestConsoleProperties consoleProperties = new GoTestConsoleProperties(myConfiguration, executor);
String frameworkName = myConfiguration.getTestFramework().getName();
ConsoleView consoleView = SMTestRunnerConnectionUtil.createAndAttachConsole(frameworkName, processHandler, consoleProperties);
consoleView.addMessageFilter(new GoConsoleFilter(myConfiguration.getProject(), myModule, myConfiguration.getWorkingDirectoryUrl()));
ProcessTerminatedListener.attach(processHandler);
DefaultExecutionResult executionResult = new DefaultExecutionResult(consoleView, processHandler);
AbstractRerunFailedTestsAction rerunFailedTestsAction = consoleProperties.createRerunFailedTestsAction(consoleView);
if (rerunFailedTestsAction != null) {
rerunFailedTestsAction.setModelProvider(((SMTRunnerConsoleView)consoleView)::getResultsViewer);
executionResult.setRestartActions(rerunFailedTestsAction, new ToggleAutoTestAction());
}
else {
executionResult.setRestartActions(new ToggleAutoTestAction());
}
return executionResult;
}
@Override
protected GoExecutor patchExecutor(@NotNull GoExecutor executor) throws ExecutionException {
executor.withParameters("test", "-v");
executor.withParameterString(myConfiguration.getGoToolParams());
switch (myConfiguration.getKind()) {
case DIRECTORY:
String relativePath = FileUtil.getRelativePath(myConfiguration.getWorkingDirectory(),
myConfiguration.getDirectoryPath(),
File.separatorChar);
// TODO Once Go gets support for covering multiple packages the ternary condition should be reverted
// See https://golang.org/issues/6909
String pathSuffix = myCoverageFilePath == null ? "..." : ".";
if (relativePath != null && !".".equals(relativePath)) {
executor.withParameters("./" + relativePath + "/" + pathSuffix);
}
else {
executor.withParameters("./" + pathSuffix);
executor.withWorkDirectory(myConfiguration.getDirectoryPath());
}
addFilterParameter(executor, ObjectUtils.notNull(myFailedTestsPattern, myConfiguration.getPattern()));
break;
case PACKAGE:
executor.withParameters(myConfiguration.getPackage());
addFilterParameter(executor, ObjectUtils.notNull(myFailedTestsPattern, myConfiguration.getPattern()));
break;
case FILE:
String filePath = myConfiguration.getFilePath();
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(filePath);
if (virtualFile == null) {
throw new ExecutionException("Test file doesn't exist");
}
PsiFile file = PsiManager.getInstance(myConfiguration.getProject()).findFile(virtualFile);
if (file == null || !GoTestFinder.isTestFile(file)) {
throw new ExecutionException("File '" + filePath + "' is not test file");
}
String importPath = ((GoFile)file).getImportPath(false);
if (StringUtil.isEmpty(importPath)) {
throw new ExecutionException("Cannot find import path for " + filePath);
}
executor.withParameters(importPath);
addFilterParameter(executor, myFailedTestsPattern != null ? myFailedTestsPattern : buildFilterPatternForFile((GoFile)file));
break;
}
if (myCoverageFilePath != null) {
executor.withParameters("-coverprofile=" + myCoverageFilePath, "-covermode=atomic");
}
return executor;
}
@NotNull
protected String buildFilterPatternForFile(GoFile file) {
Collection<String> testNames = ContainerUtil.newLinkedHashSet();
for (GoFunctionDeclaration function : file.getFunctions()) {
ContainerUtil.addIfNotNull(testNames, GoTestFinder.isTestOrExampleFunction(function) ? function.getName() : null);
}
return "^" + StringUtil.join(testNames, "|") + "$";
}
protected void addFilterParameter(@NotNull GoExecutor executor, String pattern) {
if (StringUtil.isNotEmpty(pattern)) {
executor.withParameters("-run", pattern);
}
}
public void setCoverageFilePath(@Nullable String coverageFile) {
myCoverageFilePath = coverageFile;
}
public void setFailedTests(@NotNull List<AbstractTestProxy> failedTests) {
myFailedTestsPattern = "^" + StringUtil.join(failedTests, AbstractTestProxy::getName, "|") + "$";
}
}