summaryrefslogtreecommitdiff
path: root/python/testSrc/com/jetbrains/env/python/dotNet/SkeletonTestTask.java
blob: e10916cbe7def505603be670b10c84d8016fe723 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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;
  }
}