2 * Copyright 2000-2016 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.jetbrains.python;
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;
31 import java.io.IOException;
37 public class PyQuickDocTest extends LightMarkedTestCase {
38 private PythonDocumentationProvider myProvider;
39 private DocStringFormat myFormat;
42 protected void setUp() throws Exception {
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);
52 public void tearDown() throws Exception {
53 final PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
54 documentationSettings.setFormat(myFormat);
58 private void checkByHTML(String text) {
60 checkByHTML(text, "/quickdoc/" + getTestName(false) + ".html");
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);
70 loadedText = VfsUtilCore.loadText(virtualFile);
72 catch (IOException e) {
73 throw new RuntimeException(e);
75 String fileText = StringUtil.convertLineSeparators(loadedText, "\n");
76 assertEquals(fileText.trim(), text.trim());
80 protected Map<String, PsiElement> loadTest() {
81 return configureByFile("/quickdoc/" + getTestName(false) + ".py");
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);
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());
98 checkByHTML(myProvider.generateDoc(docOwner, originalElement));
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));
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));
117 public void testDirectFunc() {
121 public void testIndented() {
125 public void testDirectClass() {
129 public void testClassConstructor() {
133 public void testClassUndocumentedConstructor() {
137 public void testClassUndocumentedEmptyConstructor() {
141 public void testCallFunc() {
145 public void testModule() {
149 public void testMethod() {
154 public void testVariable() {
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);
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!
171 checkByHTML(myProvider.generateDoc(docOwner, null));
174 public void testPropNewGetter() {
178 public void testPropNewSetter() {
179 PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
180 Map<String, PsiElement> marks = loadTest();
181 PsiElement referenceElement = marks.get("<the_ref>");
183 final PyDocStringOwner docStringOwner = (PyDocStringOwner)((PyTargetExpression)(referenceElement.getParent())).getReference().resolve();
184 checkByHTML(myProvider.generateDoc(docStringOwner, referenceElement));
187 PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
191 public void testPropNewDeleter() {
192 PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
193 Map<String, PsiElement> marks = loadTest();
194 PsiElement referenceElement = marks.get("<the_ref>");
196 final PyDocStringOwner docStringOwner = (PyDocStringOwner)((PyReferenceExpression)(referenceElement.getParent())).getReference().resolve();
197 checkByHTML(myProvider.generateDoc(docStringOwner, referenceElement));
200 PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
204 public void testPropOldGetter() {
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));
216 public void testPropOldDeleter() {
220 public void testParam() {
224 public void testInstanceAttr() {
228 public void testClassAttr() {
232 public void testHoverOverClass() {
236 public void testHoverOverFunction() {
240 public void testHoverOverMethod() {
244 public void testHoverOverParameter() {
248 public void testHoverOverControlFlowUnion() {
252 public void testReturnKeyword() {
253 Map<String, PsiElement> marks = loadTest();
254 final PsiElement originalElement = marks.get("<the_ref>");
255 checkByHTML(myProvider.generateDoc(originalElement, originalElement));
259 public void testNumPyOnesDoc() {
260 myFixture.copyDirectoryToProject("/quickdoc/" + getTestName(false), "");
265 public void testOptionalParameterType() {
266 runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
269 public void testHomogeneousTuple() {
270 runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
273 public void testHeterogeneousTuple() {
274 runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
277 public void testUnknownTuple() {
278 runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
281 public void testTypeVars() {
282 myFixture.copyDirectoryToProject("typing", "");
283 runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
287 public void testOptionalAndUnionTypesContainingTypeVars() {
288 myFixture.copyDirectoryToProject("typing", "");
289 runWithLanguageLevel(LanguageLevel.PYTHON36, this::checkHTMLOnly);
293 public void testBuiltinLen() {