/*
* 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.psi.GoFunctionOrMethodDeclaration;
import com.goide.psi.GoMethodDeclaration;
import com.goide.runconfig.GoRunUtil;
import com.goide.sdk.GoSdkService;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class GoTestRunConfigurationProducerBase extends RunConfigurationProducer<GoTestRunConfiguration> {
@NotNull private final GoTestFramework myFramework;
protected GoTestRunConfigurationProducerBase(@NotNull GoTestFramework framework) {
super(GoTestRunConfigurationType.getInstance());
myFramework = framework;
}
@Override
protected boolean setupConfigurationFromContext(@NotNull GoTestRunConfiguration configuration,
ConfigurationContext context,
Ref sourceElement) {
PsiElement contextElement = GoRunUtil.getContextElement(context);
if (contextElement == null) {
return false;
}
Module module = ModuleUtilCore.findModuleForPsiElement(contextElement);
Project project = contextElement.getProject();
if (module == null || !GoSdkService.getInstance(project).isGoModule(module)) return false;
if (!myFramework.isAvailable(module)) return false;
configuration.setModule(module);
configuration.setTestFramework(myFramework);
if (contextElement instanceof PsiDirectory) {
configuration.setName(getPackageConfigurationName(((PsiDirectory)contextElement).getName()));
configuration.setKind(GoTestRunConfiguration.Kind.DIRECTORY);
String directoryPath = ((PsiDirectory)contextElement).getVirtualFile().getPath();
configuration.setDirectoryPath(directoryPath);
configuration.setWorkingDirectory(directoryPath);
return true;
}
PsiFile file = contextElement.getContainingFile();
if (myFramework.isAvailableOnFile(file)) {
String importPath = ((GoFile)file).getImportPath(false);
if (GoRunUtil.isPackageContext(contextElement) && StringUtil.isNotEmpty(importPath)) {
configuration.setKind(GoTestRunConfiguration.Kind.PACKAGE);
configuration.setPackage(importPath);
configuration.setName(getPackageConfigurationName(importPath));
return true;
}
else {
GoFunctionOrMethodDeclaration function = findTestFunctionInContext(contextElement);
if (function != null) {
if (myFramework.isAvailableOnFunction(function)) {
configuration.setName(getFunctionConfigurationName(function, file.getName()));
configuration.setPattern("^" + function.getName() + "$");
configuration.setKind(GoTestRunConfiguration.Kind.PACKAGE);
configuration.setPackage(StringUtil.notNullize(((GoFile)file).getImportPath(false)));
return true;
}
}
else if (hasSupportedFunctions((GoFile)file)) {
configuration.setName(getFileConfigurationName(file.getName()));
configuration.setKind(GoTestRunConfiguration.Kind.FILE);
configuration.setFilePath(file.getVirtualFile().getPath());
return true;
}
}
}
return false;
}
private boolean hasSupportedFunctions(@NotNull GoFile file) {
for (GoFunctionDeclaration declaration : file.getFunctions()) {
if (myFramework.isAvailableOnFunction(declaration)) {
return true;
}
}
for (GoMethodDeclaration declaration : file.getMethods()) {
if (myFramework.isAvailableOnFunction(declaration)) {
return true;
}
}
return false;
}
@NotNull
protected String getFileConfigurationName(@NotNull String fileName) {
return fileName;
}
@NotNull
protected String getFunctionConfigurationName(@NotNull GoFunctionOrMethodDeclaration function, @NotNull String fileName) {
return function.getName() + " in " + fileName;
}
@NotNull
protected String getPackageConfigurationName(@NotNull String packageName) {
return "All in '" + packageName + "'";
}
@Override
public boolean isConfigurationFromContext(@NotNull GoTestRunConfiguration configuration, ConfigurationContext context) {
PsiElement contextElement = GoRunUtil.getContextElement(context);
if (contextElement == null) return false;
Module module = ModuleUtilCore.findModuleForPsiElement(contextElement);
if (!Comparing.equal(module, configuration.getConfigurationModule().getModule())) return false;
if (!Comparing.equal(myFramework, configuration.getTestFramework())) return false;
PsiFile file = contextElement.getContainingFile();
switch (configuration.getKind()) {
case DIRECTORY:
if (contextElement instanceof PsiDirectory) {
String directoryPath = ((PsiDirectory)contextElement).getVirtualFile().getPath();
return FileUtil.pathsEqual(configuration.getDirectoryPath(), directoryPath) &&
FileUtil.pathsEqual(configuration.getWorkingDirectory(), directoryPath);
}
case PACKAGE:
if (!GoTestFinder.isTestFile(file)) return false;
if (!Comparing.equal(((GoFile)file).getImportPath(false), configuration.getPackage())) return false;
if (GoRunUtil.isPackageContext(contextElement) && configuration.getPattern().isEmpty()) return true;
GoFunctionOrMethodDeclaration contextFunction = findTestFunctionInContext(contextElement);
return contextFunction != null && myFramework.isAvailableOnFunction(contextFunction)
? configuration.getPattern().equals("^" + contextFunction.getName() + "$")
: configuration.getPattern().isEmpty();
case FILE:
GoFunctionOrMethodDeclaration contextTestFunction = findTestFunctionInContext(contextElement);
return contextTestFunction == null && GoTestFinder.isTestFile(file) &&
FileUtil.pathsEqual(configuration.getFilePath(), file.getVirtualFile().getPath());
}
return false;
}
@Nullable
private static GoFunctionOrMethodDeclaration findTestFunctionInContext(@NotNull PsiElement contextElement) {
GoFunctionOrMethodDeclaration function = PsiTreeUtil.getNonStrictParentOfType(contextElement, GoFunctionOrMethodDeclaration.class);
return function != null && GoTestFunctionType.fromName(function.getName()) != null ? function : null;
}
}