blob: e10916cbe7def505603be670b10c84d8016fe723 [file] [log] [blame]
package com.jetbrains.env.python.dotNet;
import com.google.common.collect.Sets;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.env.PyExecutionFixtureTestTask;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.inspections.quickfix.GenerateBinaryStubsFix;
import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.sdk.InvalidSdkException;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdkTools.SdkCreationType;
import org.hamcrest.Matchers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
/**
* Task for test that checks skeleton generation
*
* @author Ilya.Kazakevich
*/
class SkeletonTestTask extends PyExecutionFixtureTestTask {
/**
* Tags for this task to run
*/
private static final Set<String> IRON_TAGS = Sets.newHashSet(PyIronPythonTest.IRON_TAG);
/**
* Number of seconds we wait for skeleton generation external process (should be enough)
*/
private static final int SECONDS_TO_WAIT_FOR_SKELETON_GENERATION = 20;
@Nullable
private final String myExpectedSkeletonFile;
@NotNull
private final String myModuleNameToBeGenerated;
@NotNull
private final String mySourceFileToRunGenerationOn;
@NotNull
private final String myUseQuickFixWithThisModuleOnly;
private PyFile myGeneratedSkeleton;
/**
* @param expectedSkeletonFile if you want test to compare generated result with some file, provide its name.
* Pass null if you do not want to compare result with anything (you may do it yourself with {@link #getGeneratedSkeleton()})
* @param moduleNameToBeGenerated name of module you think we should generate in dotted notation (like "System.Web" or "com.myModule").
* System will wait for skeleton file for this module to be generated
* @param sourceFileToRunGenerationOn Source file where we should run "generate stubs" on. Be sure to place "caret" on appropriate place!
* @param useQuickFixWithThisModuleOnly If there are several quick fixes in code, you may run fix only on this module.
* Pass null if you are sure there would be only one quickfix
*/
SkeletonTestTask(@Nullable final String expectedSkeletonFile,
@NotNull final String moduleNameToBeGenerated,
@NotNull final String sourceFileToRunGenerationOn,
@Nullable final String useQuickFixWithThisModuleOnly) {
myExpectedSkeletonFile = expectedSkeletonFile;
myModuleNameToBeGenerated = moduleNameToBeGenerated.replace('.', '/');
mySourceFileToRunGenerationOn = sourceFileToRunGenerationOn;
myUseQuickFixWithThisModuleOnly = useQuickFixWithThisModuleOnly != null ? useQuickFixWithThisModuleOnly : "";
}
@Override
public void runTestOn(@NotNull final String sdkHome) throws IOException, InvalidSdkException {
final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.SDK_PACKAGES_ONLY);
final File skeletonsPath = new File(PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath()));
File skeletonFileOrDirectory = new File(skeletonsPath, myModuleNameToBeGenerated); // File with module skeleton
// Module may be stored in "moduleName.py" or "moduleName/__init__.py"
if (skeletonFileOrDirectory.isDirectory()) {
skeletonFileOrDirectory = new File(skeletonFileOrDirectory, PyNames.INIT_DOT_PY);
}
else {
skeletonFileOrDirectory = new File(skeletonFileOrDirectory.getAbsolutePath() + PyNames.DOT_PY);
}
final File skeletonFile = skeletonFileOrDirectory;
if (skeletonFile.exists()) { // To make sure we do not reuse it
assert skeletonFile.delete() : "Failed to delete file " + skeletonFile;
}
myFixture.copyFileToProject("dotNet/" + mySourceFileToRunGenerationOn, mySourceFileToRunGenerationOn); // File that uses CLR library
myFixture.copyFileToProject("dotNet/PythonLibs.dll", "PythonLibs.dll"); // Library itself
myFixture.copyFileToProject("dotNet/SingleNameSpace.dll", "SingleNameSpace.dll"); // Another library
myFixture.configureByFile(mySourceFileToRunGenerationOn);
myFixture.enableInspections(PyUnresolvedReferencesInspection.class); // This inspection should suggest us to generate stubs
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
PsiDocumentManager.getInstance(myFixture.getProject()).commitAllDocuments();
final String intentionName = PyBundle.message("sdk.gen.stubs.for.binary.modules", myUseQuickFixWithThisModuleOnly);
final IntentionAction intention = myFixture.findSingleIntention(intentionName);
Assert.assertNotNull("No intention found to generate skeletons!", intention);
Assert.assertThat("Intention should be quick fix to run", intention, Matchers.instanceOf(QuickFixWrapper.class));
final LocalQuickFix quickFix = ((QuickFixWrapper)intention).getFix();
Assert.assertThat("Quick fix should be 'generate binary skeletons' fix to run", quickFix,
Matchers.instanceOf(GenerateBinaryStubsFix.class));
final Task fixTask = ((GenerateBinaryStubsFix)quickFix).getFixTask(myFixture.getFile());
fixTask.run(new AbstractProgressIndicatorBase());
}
});
FileUtil.copy(skeletonFile, new File(myFixture.getTempDirPath(), skeletonFile.getName()));
if (myExpectedSkeletonFile != null) {
myFixture.checkResultByFile(skeletonFile.getName(), myExpectedSkeletonFile, false);
}
myGeneratedSkeleton = (PyFile)myFixture.configureByFile(skeletonFile.getName());
}
@Override
public Set<String> getTags() {
return Collections.unmodifiableSet(IRON_TAGS);
}
/**
* @return File for generated skeleton. Call it after {@link #runTestOn(String)} only!
*/
@NotNull
PyFile getGeneratedSkeleton() {
return myGeneratedSkeleton;
}
}