package com.jetbrains.lang.dart.ide.runner.test;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.RunConfigurationProducer;
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.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.lang.dart.ide.runner.server.DartCommandLineRuntimeConfigurationProducer;
import com.jetbrains.lang.dart.ide.runner.util.TestUtil;
import com.jetbrains.lang.dart.psi.DartCallExpression;
import com.jetbrains.lang.dart.psi.DartFile;
import com.jetbrains.lang.dart.util.DartResolveUtil;
import com.jetbrains.lang.dart.util.DartUrlResolver;
import com.jetbrains.lang.dart.util.PubspecYamlUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class DartTestRunConfigurationProducer extends RunConfigurationProducer<DartTestRunConfiguration> {
public DartTestRunConfigurationProducer() {
super(DartTestRunConfigurationType.getInstance());
}
@Override
protected boolean setupConfigurationFromContext(final @NotNull DartTestRunConfiguration configuration,
final @NotNull ConfigurationContext context,
final @NotNull Ref<PsiElement> sourceElement) {
final boolean ok;
final PsiElement location = context.getPsiLocation();
if (location instanceof PsiDirectory) {
ok = setupRunnerParametersForFolderIfApplicable(configuration.getProject(), configuration.getRunnerParameters(),
((PsiDirectory)location).getVirtualFile());
}
else {
ok = setupRunnerParametersForFileIfApplicable(configuration.getRunnerParameters(), context, sourceElement);
}
if (ok) {
configuration.setGeneratedName();
}
return ok;
}
@Override
public boolean isConfigurationFromContext(@NotNull final DartTestRunConfiguration configuration,
@NotNull final ConfigurationContext context) {
final DartTestRunnerParameters existingParams = configuration.getRunnerParameters();
final DartTestRunnerParameters paramsFromContext = new DartTestRunnerParameters();
final PsiElement location = context.getPsiLocation();
if (location instanceof PsiDirectory) {
if (!setupRunnerParametersForFolder(paramsFromContext, ((PsiDirectory)location).getVirtualFile())) return false;
}
else {
final PsiElement testElement = TestUtil.findTestElement(location);
if (testElement == null || !setupRunnerParametersForFile(paramsFromContext, testElement)) return false;
}
return Comparing.equal(existingParams.getFilePath(), paramsFromContext.getFilePath()) &&
Comparing.equal(existingParams.getScope(), paramsFromContext.getScope()) &&
(existingParams.getScope() != DartTestRunnerParameters.Scope.GROUP_OR_TEST_BY_NAME ||
Comparing.equal(existingParams.getTestName(), paramsFromContext.getTestName()));
}
private static boolean setupRunnerParametersForFolderIfApplicable(@NotNull final Project project,
@NotNull final DartTestRunnerParameters params,
@NotNull final VirtualFile dir) {
final DartUrlResolver urlResolver = DartUrlResolver.getInstance(project, dir);
final VirtualFile dartTestLib = urlResolver.findFileByDartUrl("package:test/test.dart");
if (dartTestLib == null) return false;
final VirtualFile pubspec = urlResolver.getPubspecYamlFile();
final VirtualFile rootDir = pubspec == null ? null : pubspec.getParent();
final VirtualFile testDir = rootDir == null ? null : rootDir.findChild("test");
if (testDir == null || !testDir.isDirectory()) return false;
if (!rootDir.equals(dir) && !VfsUtilCore.isAncestor(testDir, dir, false)) return false;
return setupRunnerParametersForFolder(params, dir);
}
private static boolean setupRunnerParametersForFolder(@NotNull final DartTestRunnerParameters params, @NotNull VirtualFile dir) {
if ("test".equals(dir.getName()) &&
dir.findChild(PubspecYamlUtil.PUBSPEC_YAML) == null &&
dir.getParent().findChild(PubspecYamlUtil.PUBSPEC_YAML) != null) {
dir = dir.getParent(); // anyway test engine looks for tests in 'test' subfolder only
}
params.setScope(DartTestRunnerParameters.Scope.FOLDER);
params.setFilePath(dir.getPath());
return true;
}
private static boolean setupRunnerParametersForFileIfApplicable(@NotNull final DartTestRunnerParameters params,
@NotNull final ConfigurationContext context,
@NotNull final Ref<PsiElement> sourceElement) {
final VirtualFile dartFile = DartCommandLineRuntimeConfigurationProducer.getRunnableDartFileFromContext(context, false);
if (dartFile == null || !isFileInTestDirAndTestPackageExists(context.getProject(), dartFile)) return false;
final PsiElement testElement = TestUtil.findTestElement(context.getPsiLocation());
if (testElement == null || !setupRunnerParametersForFile(params, testElement)) {
return false;
}
sourceElement.set(testElement);
return true;
}
public static boolean isFileInTestDirAndTestPackageExists(@NotNull final Project project, @NotNull final VirtualFile file) {
final DartUrlResolver urlResolver = DartUrlResolver.getInstance(project, file);
final VirtualFile dartTestLib = urlResolver.findFileByDartUrl("package:test/test.dart");
if (dartTestLib == null) return false;
final VirtualFile pubspec = urlResolver.getPubspecYamlFile();
final VirtualFile rootDir = pubspec == null ? null : pubspec.getParent();
final VirtualFile testDir = rootDir == null ? null : rootDir.findChild("test");
return testDir != null && testDir.isDirectory() && VfsUtilCore.isAncestor(testDir, file, true);
}
private static boolean setupRunnerParametersForFile(@NotNull final DartTestRunnerParameters runnerParams,
@NotNull final PsiElement psiElement) {
if (psiElement instanceof DartCallExpression) {
final String testName = TestUtil.findGroupOrTestName((DartCallExpression)psiElement);
final List<VirtualFile> virtualFiles = DartResolveUtil.findLibrary(psiElement.getContainingFile());
if (testName == null || virtualFiles.isEmpty()) {
return false;
}
runnerParams.setTestName(testName);
runnerParams.setScope(DartTestRunnerParameters.Scope.GROUP_OR_TEST_BY_NAME);
final VirtualFile dartFile = virtualFiles.iterator().next();
final String dartFilePath = dartFile.getPath();
runnerParams.setFilePath(dartFilePath);
return true;
}
else {
final PsiFile psiFile = psiElement.getContainingFile();
if (psiFile instanceof DartFile) {
final VirtualFile virtualFile = DartResolveUtil.getRealVirtualFile((DartFile)psiElement);
if (virtualFile == null || !DartResolveUtil.isLibraryRoot((DartFile)psiElement)) {
return false;
}
runnerParams.setTestName(DartResolveUtil.getLibraryName((DartFile)psiElement));
runnerParams.setScope(DartTestRunnerParameters.Scope.FILE);
final String dartFilePath = FileUtil.toSystemIndependentName(virtualFile.getPath());
runnerParams.setFilePath(dartFilePath);
return true;
}
}
return false;
}
}