Use documentation from Python stubs for Quick Documentation view (PY-22685)
[idea/community.git] / python / testSrc / com / jetbrains / python / PyQuickDocTest.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.python;
17
18 import com.intellij.openapi.util.text.StringUtil;
19 import com.intellij.openapi.vfs.VfsUtilCore;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.psi.PsiElement;
22 import com.intellij.testFramework.TestDataFile;
23 import com.jetbrains.python.documentation.PyDocumentationSettings;
24 import com.jetbrains.python.documentation.PythonDocumentationProvider;
25 import com.jetbrains.python.documentation.docstrings.DocStringFormat;
26 import com.jetbrains.python.fixtures.LightMarkedTestCase;
27 import com.jetbrains.python.fixtures.PyTestCase;
28 import com.jetbrains.python.psi.*;
29 import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
30
31 import java.io.IOException;
32 import java.util.Map;
33
34 /**
35  * @author dcheryasov
36  */
37 public class PyQuickDocTest extends LightMarkedTestCase {
38   private PythonDocumentationProvider myProvider;
39   private DocStringFormat myFormat;
40
41   @Override
42   protected void setUp() throws Exception {
43     super.setUp();
44     // the provider is stateless, can be reused, as in real life
45     myProvider = new PythonDocumentationProvider();
46     final PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
47     myFormat = documentationSettings.getFormat();
48     documentationSettings.setFormat(DocStringFormat.PLAIN);
49   }
50
51   @Override
52   public void tearDown() throws Exception {
53     final PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
54     documentationSettings.setFormat(myFormat);
55     super.tearDown();
56   }
57
58   private void checkByHTML(String text) {
59     assertNotNull(text);
60     checkByHTML(text, "/quickdoc/" + getTestName(false) + ".html");
61   }
62
63   private void checkByHTML(String text, @TestDataFile String filePath) {
64     final String fullPath = getTestDataPath() + filePath;
65     final VirtualFile virtualFile = PyTestCase.getVirtualFileByName(fullPath);
66     assertNotNull("file " + fullPath + " not found", virtualFile);
67
68     String loadedText;
69     try {
70       loadedText = VfsUtilCore.loadText(virtualFile);
71     }
72     catch (IOException e) {
73       throw new RuntimeException(e);
74     }
75     String fileText = StringUtil.convertLineSeparators(loadedText, "\n");
76     assertEquals(fileText.trim(), text.trim());
77   }
78
79   @Override
80   protected Map<String, PsiElement> loadTest() {
81     return configureByFile("/quickdoc/" + getTestName(false) + ".py");
82   }
83
84   private void checkRefDocPair() {
85     Map<String, PsiElement> marks = loadTest();
86     assertEquals(2, marks.size());
87     final PsiElement originalElement = marks.get("<the_doc>");
88     PsiElement docElement = originalElement.getParent(); // ident -> expr
89     assertTrue(docElement instanceof PyStringLiteralExpression);
90     String stringValue = ((PyStringLiteralExpression)docElement).getStringValue();
91     assertNotNull(stringValue);
92
93     PsiElement referenceElement = marks.get("<the_ref>").getParent(); // ident -> expr
94     final PyDocStringOwner docOwner = (PyDocStringOwner)((PyReferenceExpression)referenceElement).getReference().resolve();
95     assertNotNull(docOwner);
96     assertEquals(docElement, docOwner.getDocStringExpression());
97
98     checkByHTML(myProvider.generateDoc(docOwner, originalElement));
99   }
100
101   private void checkHTMLOnly() {
102     Map<String, PsiElement> marks = loadTest();
103     final PsiElement originalElement = marks.get("<the_ref>");
104     PsiElement referenceElement = originalElement.getParent(); // ident -> expr
105     final PsiElement docOwner = ((PyReferenceExpression)referenceElement).getReference().resolve();
106     checkByHTML(myProvider.generateDoc(docOwner, originalElement));
107   }
108
109   private void checkHover() {
110     Map<String, PsiElement> marks = loadTest();
111     final PsiElement originalElement = marks.get("<the_ref>");
112     PsiElement referenceElement = originalElement.getParent(); // ident -> expr
113     final PsiElement docOwner = ((PyReferenceExpression)referenceElement).getReference().resolve();
114     checkByHTML(myProvider.getQuickNavigateInfo(docOwner, referenceElement));
115   }
116
117   public void testDirectFunc() {
118     checkRefDocPair();
119   }
120
121   public void testIndented() {
122     checkRefDocPair();
123   }
124
125   public void testDirectClass() {
126     checkRefDocPair();
127   }
128
129   public void testClassConstructor() {
130     checkRefDocPair();
131   }
132
133   public void testClassUndocumentedConstructor() {
134     checkHTMLOnly();
135   }
136
137   public void testClassUndocumentedEmptyConstructor() {
138     checkHTMLOnly();
139   }
140
141   public void testCallFunc() {
142     checkRefDocPair();
143   }
144
145   public void testModule() {
146     checkRefDocPair();
147   }
148
149   public void testMethod() {
150     checkRefDocPair();
151   }
152
153   // PY-3496
154   public void testVariable() {
155     checkHTMLOnly();
156   }
157
158   public void testInheritedMethod() {
159     Map<String, PsiElement> marks = loadTest();
160     assertEquals(2, marks.size());
161     PsiElement docElement = marks.get("<the_doc>").getParent(); // ident -> expr
162     assertTrue(docElement instanceof PyStringLiteralExpression);
163     String docText = ((PyStringLiteralExpression)docElement).getStringValue();
164     assertNotNull(docText);
165
166     PsiElement ref_elt = marks.get("<the_ref>").getParent(); // ident -> expr
167     final PyDocStringOwner docOwner = (PyDocStringOwner)((PyReferenceExpression)ref_elt).getReference().resolve();
168     assertNotNull(docOwner);
169     assertNull(docOwner.getDocStringExpression()); // no direct doc!
170
171     checkByHTML(myProvider.generateDoc(docOwner, null));
172   }
173
174   public void testPropNewGetter() {
175     checkHTMLOnly();
176   }
177
178   public void testPropNewSetter() {
179     PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
180     Map<String, PsiElement> marks = loadTest();
181     PsiElement referenceElement = marks.get("<the_ref>");
182     try {
183       final PyDocStringOwner docStringOwner = (PyDocStringOwner)((PyTargetExpression)(referenceElement.getParent())).getReference().resolve();
184       checkByHTML(myProvider.generateDoc(docStringOwner, referenceElement));
185     }
186     finally {
187       PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
188     }
189   }
190
191   public void testPropNewDeleter() {
192     PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
193     Map<String, PsiElement> marks = loadTest();
194     PsiElement referenceElement = marks.get("<the_ref>");
195     try {
196       final PyDocStringOwner docStringOwner = (PyDocStringOwner)((PyReferenceExpression)(referenceElement.getParent())).getReference().resolve();
197       checkByHTML(myProvider.generateDoc(docStringOwner, referenceElement));
198     }
199     finally {
200       PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
201     }
202   }
203
204   public void testPropOldGetter() {
205     checkHTMLOnly();
206   }
207
208
209   public void testPropOldSetter() {
210     Map<String, PsiElement> marks = loadTest();
211     PsiElement referenceElement = marks.get("<the_ref>");
212     final PyDocStringOwner docStringOwner = (PyDocStringOwner)((PyTargetExpression)(referenceElement.getParent())).getReference().resolve();
213     checkByHTML(myProvider.generateDoc(docStringOwner, referenceElement));
214   }
215
216   public void testPropOldDeleter() {
217     checkHTMLOnly();
218   }
219
220   public void testParam() {
221     checkHTMLOnly();
222   }
223
224   public void testInstanceAttr() {
225     checkHTMLOnly();
226   }
227
228   public void testClassAttr() {
229     checkHTMLOnly();
230   }
231
232   public void testHoverOverClass() {
233     checkHover();
234   }
235
236   public void testHoverOverFunction() {
237     checkHover();
238   }
239
240   public void testHoverOverMethod() {
241     checkHover();
242   }
243
244   public void testHoverOverParameter() {
245     checkHover();
246   }
247
248   public void testHoverOverControlFlowUnion() {
249     checkHover();
250   }
251
252   public void testReturnKeyword() {
253     Map<String, PsiElement> marks = loadTest();
254     final PsiElement originalElement = marks.get("<the_ref>");
255     checkByHTML(myProvider.generateDoc(originalElement, originalElement));
256   }
257
258   // PY-13422
259   public void testNumPyOnesDoc() {
260     myFixture.copyDirectoryToProject("/quickdoc/" + getTestName(false), "");
261     checkHover();
262   }
263
264   // PY-17705
265   public void testOptionalParameterType() {
266     runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
267   }
268
269   public void testHomogeneousTuple() {
270     runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
271   }
272
273   public void testHeterogeneousTuple() {
274     runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
275   }
276
277   public void testUnknownTuple() {
278     runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
279   }
280
281   public void testTypeVars() {
282     myFixture.copyDirectoryToProject("typing", "");
283     runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
284   }
285   
286   // PY-22730
287   public void testOptionalAndUnionTypesContainingTypeVars() {
288     myFixture.copyDirectoryToProject("typing", "");
289     runWithLanguageLevel(LanguageLevel.PYTHON36, this::checkHTMLOnly);
290   }
291
292   // PY-22685
293   public void testBuiltinLen() {
294     checkHTMLOnly();
295   }
296 }