// Copyright 2016 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).
package com.twitter.intellij.pants.execution;
import com.intellij.execution.Location;
import com.intellij.execution.PsiLocation;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.MapDataContext;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.impl.PyClassImpl;
import com.jetbrains.python.psi.impl.PyFileImpl;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.PyClassTypeImpl;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.testing.pytest.PyTestUtil;
import com.twitter.intellij.pants.testFramework.OSSPantsIntegrationTest;
import com.twitter.intellij.pants.util.PantsConstants;
import com.twitter.intellij.pants.util.PantsUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class OSSPantsPythonRunConfigurationIntegrationTest extends OSSPantsIntegrationTest {
public void testPyTestRunConfiguration() throws Throwable {
doImport("examples/tests/python/example_test/hello");
PyClass pyClass = PyClassNameIndex.find("GreetTest", myProject, true).iterator().next();
PyClass truClass = new PyTestClass(pyClass);
assertTrue(PyTestUtil.isPyTestClass(truClass, null));
PsiFile file = new PyTestFile(truClass.getContainingFile(), truClass);
ExternalSystemRunConfiguration esc = getExternalSystemRunConfiguration(file);
List<String> items = PantsUtil.parseCmdParameters(Optional.ofNullable(esc.getSettings().getScriptParameters()));
assertNotContainsSubstring(items, PantsConstants.PANTS_CLI_OPTION_JUNIT_TEST);
assertContainsSubstring(items, PantsConstants.PANTS_CLI_OPTION_PYTEST);
}
@NotNull
private ExternalSystemRunConfiguration getExternalSystemRunConfiguration(PsiElement psiElement) {
ConfigurationContext context = createContext(psiElement, new MapDataContext());
ConfigurationFromContext myPantsConfigurationFromContext = getPantsPytestConfigurationFromContext(context);
assertNotNull(myPantsConfigurationFromContext);
return (ExternalSystemRunConfiguration) myPantsConfigurationFromContext.getConfiguration();
}
private ConfigurationFromContext getPantsPytestConfigurationFromContext(ConfigurationContext context) {
for (RunConfigurationProducer producer : RunConfigurationProducer.getProducers(myProject)) {
if (producer instanceof PantsPythonTestRunConfigurationProducer) {
return producer.createConfigurationFromContext(context);
}
}
return null;
}
private ConfigurationContext createContext(@NotNull PsiElement psiClass, @NotNull MapDataContext dataContext) {
dataContext.put(CommonDataKeys.PROJECT, myProject);
if (LangDataKeys.MODULE.getData(dataContext) == null) {
dataContext.put(LangDataKeys.MODULE, ModuleUtilCore.findModuleForPsiElement(psiClass));
}
dataContext.put(Location.DATA_KEY, PsiLocation.fromPsiElement(psiClass));
return ConfigurationContext.getFromContext(dataContext);
}
// The classes below are created to correctly form a context for python testing
private static class PyTestFile extends PyFileImpl {
private PyClass myTestClass;
private PyTestFile(PsiFile pyFile, PyClass testClass) {
super(pyFile.getViewProvider());
myTestClass = testClass;
}
@Override
public List<PyClass> getTopLevelClasses() {
return Collections.singletonList(myTestClass);
}
}
private static class PyTestClass extends PyClassImpl {
PyClass within;
private PyTestClass(PyClass pyClass) {
super(pyClass.getNameNode());
within = pyClass;
}
@NotNull
public List<PyClassLikeType> getAncestorTypes(@NotNull TypeEvalContext context) {
ArrayList<PyClassLikeType> ancestors = new ArrayList<PyClassLikeType>();
ancestors.add(new AncestorPyClass(within));
return ancestors;
}
}
private static class AncestorPyClass extends PyClassTypeImpl {
private AncestorPyClass(@NotNull PyClass source) {
super(source, true);
}
@Override
public String getClassQName() {
return "unittest.TestCase";
}
}
}