mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
586 lines
21 KiB
Java
586 lines
21 KiB
Java
/*
|
|
* Copyright 2000-2016 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.jetbrains.python;
|
|
|
|
import com.intellij.lang.FileASTNode;
|
|
import com.intellij.openapi.application.Result;
|
|
import com.intellij.openapi.command.WriteCommandAction;
|
|
import com.intellij.openapi.editor.Document;
|
|
import com.intellij.openapi.project.DumbServiceImpl;
|
|
import com.intellij.openapi.project.Project;
|
|
import com.intellij.openapi.vfs.VirtualFile;
|
|
import com.intellij.psi.*;
|
|
import com.intellij.psi.impl.source.PsiFileImpl;
|
|
import com.intellij.psi.search.GlobalSearchScope;
|
|
import com.intellij.psi.stubs.StubElement;
|
|
import com.intellij.psi.util.QualifiedName;
|
|
import com.intellij.testFramework.TestDataPath;
|
|
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
|
|
import com.jetbrains.python.fixtures.PyTestCase;
|
|
import com.jetbrains.python.psi.*;
|
|
import com.jetbrains.python.psi.impl.PyFileImpl;
|
|
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
|
|
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
|
|
import com.jetbrains.python.psi.stubs.PyNamedTupleStub;
|
|
import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
|
|
import com.jetbrains.python.psi.types.PyClassType;
|
|
import com.jetbrains.python.psi.types.PyType;
|
|
import com.jetbrains.python.psi.types.TypeEvalContext;
|
|
import com.jetbrains.python.toolbox.Maybe;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* @author max
|
|
* @author yole
|
|
*/
|
|
@TestDataPath("$CONTENT_ROOT/../testData/stubs/")
|
|
public class PyStubsTest extends PyTestCase {
|
|
|
|
@Override
|
|
protected String getTestDataPath() {
|
|
return PythonTestUtil.getTestDataPath() + "/stubs/";
|
|
}
|
|
|
|
public void testStubStructure() {
|
|
// vfile is problematic, but we need an SDK to check builtins
|
|
final Project project = myFixture.getProject();
|
|
|
|
PythonLanguageLevelPusher.setForcedLanguageLevel(project, LanguageLevel.PYTHON26); // we need 2.6+ for @foo.setter
|
|
try {
|
|
final PyFile file = getTestFile();
|
|
final List<PyClass> classes = file.getTopLevelClasses();
|
|
assertEquals(3, classes.size());
|
|
PyClass pyClass = classes.get(0);
|
|
assertEquals("FooClass", pyClass.getName());
|
|
assertEquals("StubStructure.FooClass", pyClass.getQualifiedName());
|
|
|
|
final List<PyTargetExpression> attrs = pyClass.getClassAttributes();
|
|
assertEquals(2, attrs.size());
|
|
assertEquals("staticField", attrs.get(0).getName());
|
|
assertTrue(attrs.get(0).getAssignedQName().matches("deco"));
|
|
|
|
final PyFunction[] methods = pyClass.getMethods();
|
|
assertEquals(2, methods.length);
|
|
assertEquals("__init__", methods [0].getName());
|
|
assertEquals("fooFunction", methods [1].getName());
|
|
|
|
final PyParameter[] parameters = methods[1].getParameterList().getParameters();
|
|
assertFalse(parameters [0].hasDefaultValue());
|
|
assertTrue(parameters [1].hasDefaultValue());
|
|
|
|
// decorators
|
|
PyFunction decorated = methods[1];
|
|
PyDecoratorList decos = decorated.getDecoratorList();
|
|
assertNotNull(decos);
|
|
assertNotParsed(file);
|
|
PyDecorator[] da = decos.getDecorators();
|
|
assertNotNull(da);
|
|
assertEquals(1, da.length);
|
|
assertNotParsed(file);
|
|
PyDecorator deco = da[0];
|
|
assertNotNull(deco);
|
|
assertEquals("deco", deco.getName());
|
|
assertNotParsed(file);
|
|
|
|
final List<PyTargetExpression> instanceAttrs = pyClass.getInstanceAttributes();
|
|
assertEquals(1, instanceAttrs.size());
|
|
assertEquals("instanceField", instanceAttrs.get(0).getName());
|
|
|
|
final List<PyFunction> functions = file.getTopLevelFunctions();
|
|
assertEquals(2, functions.size()); // "deco" and "topLevelFunction"
|
|
PyFunction func = functions.get(0);
|
|
assertEquals("deco", func.getName());
|
|
|
|
func = functions.get(1);
|
|
assertEquals("topLevelFunction", func.getName());
|
|
|
|
final List<PyTargetExpression> exprs = file.getTopLevelAttributes();
|
|
assertEquals(2, exprs.size());
|
|
assertEquals("top1", exprs.get(0).getName());
|
|
assertEquals("top2", exprs.get(1).getName());
|
|
|
|
// properties by call
|
|
pyClass = classes.get(1);
|
|
assertEquals("BarClass", pyClass.getName());
|
|
|
|
Property prop = pyClass.findProperty("value", true, null);
|
|
Maybe<PyCallable> maybe_function = prop.getGetter();
|
|
assertTrue(maybe_function.isDefined());
|
|
assertEquals(pyClass.getMethods()[0], maybe_function.value());
|
|
|
|
Property setvalueProp = pyClass.findProperty("setvalue", true, null);
|
|
Maybe<PyCallable> setter = setvalueProp.getSetter();
|
|
assertTrue(setter.isDefined());
|
|
assertEquals("__set", setter.value().getName());
|
|
|
|
// properties by decorator
|
|
pyClass = classes.get(2);
|
|
assertEquals("BazClass", pyClass.getName());
|
|
prop = pyClass.findProperty("x", true, null);
|
|
maybe_function = prop.getGetter();
|
|
assertTrue(maybe_function.isDefined());
|
|
assertEquals(pyClass.getMethods()[0], maybe_function.value());
|
|
maybe_function = prop.getSetter();
|
|
assertTrue(maybe_function.isDefined());
|
|
assertEquals(pyClass.getMethods()[1], maybe_function.value());
|
|
|
|
// ...and the juice:
|
|
assertNotParsed(file);
|
|
}
|
|
finally {
|
|
PythonLanguageLevelPusher.setForcedLanguageLevel(project, LanguageLevel.getDefault());
|
|
}
|
|
}
|
|
|
|
public void testLoadingDeeperTreeRemainsKnownPsiElement() {
|
|
final PyFile file = getTestFile();
|
|
final List<PyClass> classes = file.getTopLevelClasses();
|
|
assertEquals(1, classes.size());
|
|
PyClass pyClass = classes.get(0);
|
|
|
|
assertEquals("SomeClass", pyClass.getName());
|
|
|
|
assertNotParsed(file);
|
|
|
|
// load the tree now
|
|
final PyStatementList statements = pyClass.getStatementList();
|
|
assertNotNull(((PyFileImpl)file).getTreeElement());
|
|
|
|
final PsiElement[] children = file.getChildren();
|
|
|
|
assertEquals(1, children.length);
|
|
assertSame(pyClass, children[0]);
|
|
}
|
|
|
|
public void testLoadingTreeRetainsKnownPsiElement() {
|
|
final PyFile file = getTestFile();
|
|
final List<PyClass> classes = file.getTopLevelClasses();
|
|
assertEquals(1, classes.size());
|
|
PyClass pyClass = classes.get(0);
|
|
|
|
assertEquals("SomeClass", pyClass.getName());
|
|
|
|
assertNotParsed(file);
|
|
|
|
final PsiElement[] children = file.getChildren(); // Load the tree
|
|
|
|
assertNotNull(((PyFileImpl)file).getTreeElement());
|
|
assertEquals(1, children.length);
|
|
assertSame(pyClass, children[0]);
|
|
}
|
|
|
|
public void testRenamingUpdatesTheStub() {
|
|
final PyFile file = getTestFile("LoadingTreeRetainsKnownPsiElement.py");
|
|
final List<PyClass> classes = file.getTopLevelClasses();
|
|
assertEquals(1, classes.size());
|
|
final PyClass pyClass = classes.get(0);
|
|
|
|
assertEquals("SomeClass", pyClass.getName());
|
|
|
|
// Ensure we haven't loaded the tree yet.
|
|
final PyFileImpl fileImpl = (PyFileImpl)file;
|
|
assertNull(fileImpl.getTreeElement());
|
|
|
|
final PsiElement[] children = file.getChildren(); // Load the tree
|
|
|
|
assertNotNull(fileImpl.getTreeElement());
|
|
assertEquals(1, children.length);
|
|
assertSame(pyClass, children[0]);
|
|
|
|
new WriteCommandAction(myFixture.getProject(), fileImpl) {
|
|
@Override
|
|
protected void run(@NotNull final Result result) throws Throwable {
|
|
pyClass.setName("RenamedClass");
|
|
assertEquals("RenamedClass", pyClass.getName());
|
|
}
|
|
}.execute();
|
|
|
|
StubElement fileStub = fileImpl.getStub();
|
|
assertNull("There should be no stub if file holds tree element", fileStub);
|
|
|
|
new WriteCommandAction(myFixture.getProject(), fileImpl) {
|
|
@Override
|
|
protected void run(@NotNull Result result) throws Throwable {
|
|
((SingleRootFileViewProvider)fileImpl.getViewProvider()).onContentReload();
|
|
}
|
|
}.execute();
|
|
assertNull(fileImpl.getTreeElement()); // Test unload succeeded.
|
|
|
|
assertEquals("RenamedClass", fileImpl.getTopLevelClasses().get(0).getName());
|
|
}
|
|
|
|
public void testImportStatement() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
|
|
final List<PyFromImportStatement> fromImports = file.getFromImports();
|
|
assertEquals(1, fromImports.size());
|
|
final PyFromImportStatement fromImport = fromImports.get(0);
|
|
final PyImportElement[] importElements = fromImport.getImportElements();
|
|
assertEquals(1, importElements.length);
|
|
assertEquals("argv", importElements [0].getVisibleName());
|
|
assertFalse(fromImport.isStarImport());
|
|
assertEquals(0, fromImport.getRelativeLevel());
|
|
final QualifiedName qName = fromImport.getImportSourceQName();
|
|
assertSameElements(qName.getComponents(), "sys");
|
|
|
|
final List<PyImportElement> importTargets = file.getImportTargets();
|
|
assertEquals(1, importTargets.size());
|
|
final PyImportElement importElement = importTargets.get(0);
|
|
final QualifiedName importQName = importElement.getImportedQName();
|
|
assertSameElements(importQName.getComponents(), "os", "path");
|
|
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testDunderAll() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final List<String> all = file.getDunderAll();
|
|
assertSameElements(all, "foo", "bar");
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testDynamicDunderAll() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final List<String> all = file.getDunderAll();
|
|
assertNull(all);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testAugAssignDunderAll() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final List<String> all = file.getDunderAll();
|
|
assertNull(all);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testDunderAllAsSum() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final List<String> all = file.getDunderAll();
|
|
assertSameElements(all, "md5", "sha1", "algorithms_guaranteed", "algorithms_available");
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testSlots() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PyClass pyClass = file.getTopLevelClasses().get(0);
|
|
assertSameElements(pyClass.getSlots(null), "foo", "bar");
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testImportInTryExcept() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PsiElement element = file.findExportedName("sys");
|
|
assertTrue(element != null ? element.toString() : "null", element instanceof PyImportElement);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testNameInExcept() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PsiElement element = file.findExportedName("md5");
|
|
assertTrue(element != null ? element.toString() : "null", element instanceof PyTargetExpression);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testVariableIndex() {
|
|
getTestFile();
|
|
GlobalSearchScope scope = GlobalSearchScope.allScope(myFixture.getProject());
|
|
Collection<PyTargetExpression> result = PyVariableNameIndex.find("xyzzy", myFixture.getProject(), scope);
|
|
assertEquals(1, result.size());
|
|
assertEquals(0, PyVariableNameIndex.find("shazam", myFixture.getProject(), scope).size());
|
|
assertEquals(0, PyVariableNameIndex.find("boohoo", myFixture.getProject(), scope).size());
|
|
assertEquals(0, PyVariableNameIndex.find("__all__", myFixture.getProject(), scope).size());
|
|
}
|
|
|
|
public void testImportInExcept() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PsiElement element = file.getElementNamed("tzinfo");
|
|
assertTrue(element != null ? element.toString() : "null", element instanceof PyClass);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
|
|
public void testImportFeatures() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
assertTrue(file.hasImportFromFuture(FutureFeature.DIVISION));
|
|
assertTrue(file.hasImportFromFuture(FutureFeature.UNICODE_LITERALS));
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testIfNameMain() { // PY-4008
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
ensureVariableNotInIndex("xyzzy");
|
|
assertNotParsed(file);
|
|
file.acceptChildren(new PyRecursiveElementVisitor()); // assert no error on switching from stub to AST
|
|
assertNotNull(file.getTreeElement());
|
|
}
|
|
|
|
public void testVariableInComprehension() { // PY-4029
|
|
ensureVariableNotInIndex("xyzzy");
|
|
}
|
|
|
|
public void testWrappedStaticMethod() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PyClass pyClass = file.getTopLevelClasses().get(0);
|
|
final PyFunction[] methods = pyClass.getMethods();
|
|
assertEquals(1, methods.length);
|
|
final PyFunction.Modifier modifier = methods[0].getModifier();
|
|
assertEquals(PyFunction.Modifier.STATICMETHOD, modifier);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testBuiltinAncestor() {
|
|
final PyFileImpl file = (PyFileImpl) getTestFile();
|
|
final PyClass pyClass = file.getTopLevelClasses().get(0);
|
|
final PyClass cls = pyClass.getAncestorClasses(null).iterator().next();
|
|
assertNotNull(cls);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
private void ensureVariableNotInIndex(String name) {
|
|
getTestFile();
|
|
GlobalSearchScope scope = GlobalSearchScope.allScope(myFixture.getProject());
|
|
Collection<PyTargetExpression> result = PyVariableNameIndex.find(name, myFixture.getProject(), scope);
|
|
assertEquals(0, result.size());
|
|
}
|
|
|
|
// ---
|
|
|
|
private PyFile getTestFile() {
|
|
return getTestFile(getTestName(false) + ".py");
|
|
}
|
|
|
|
private PyFile getTestFile(final String fileName) {
|
|
VirtualFile sourceFile = myFixture.copyFileToProject(fileName);
|
|
assert sourceFile != null;
|
|
PsiFile psiFile = myFixture.getPsiManager().findFile(sourceFile);
|
|
return (PyFile)psiFile;
|
|
}
|
|
|
|
public void testStubIndexMismatch() {
|
|
VirtualFile vFile = myFixture.getTempDirFixture().createFile("foo.py");
|
|
final Project project = myFixture.getProject();
|
|
PsiFileImpl fooPyFile = (PsiFileImpl) PsiManager.getInstance(project).findFile(vFile);
|
|
assertNotNull(fooPyFile);
|
|
final Document fooDocument = fooPyFile.getViewProvider().getDocument();
|
|
assertNotNull(fooDocument);
|
|
final Collection<PyClass> classes = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project));
|
|
assertEquals(0, classes.size());
|
|
new WriteCommandAction.Simple(project, fooPyFile) {
|
|
public void run() {
|
|
fooDocument.setText("class Foo: pass");
|
|
}
|
|
}.execute();
|
|
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
|
documentManager.commitDocument(fooDocument);
|
|
documentManager.performForCommittedDocument(fooDocument, () -> {
|
|
fooPyFile.setTreeElementPointer(null);
|
|
//classes = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project));
|
|
//fooPyFile.unloadContent();
|
|
DumbServiceImpl.getInstance(project).setDumb(true);
|
|
try {
|
|
assertEquals(1, ((PyFile) fooPyFile).getTopLevelClasses().size());
|
|
assertFalse(fooPyFile.isContentsLoaded());
|
|
}
|
|
finally {
|
|
DumbServiceImpl.getInstance(project).setDumb(false);
|
|
}
|
|
final Collection<PyClass> committedClasses = PyClassNameIndex.find("Foo", project, GlobalSearchScope.allScope(project));
|
|
assertEquals(1, committedClasses.size());
|
|
});
|
|
}
|
|
|
|
public void testTargetExpressionDocString() {
|
|
final PyFile file = getTestFile();
|
|
final PyClass c = file.findTopLevelClass("C");
|
|
assertNotNull(c);
|
|
final PyTargetExpression foo = c.findClassAttribute("foo", false, null);
|
|
final String docString = foo.getDocStringValue();
|
|
assertEquals("Foo docstring.", docString);
|
|
}
|
|
|
|
public void testMetaClass() {
|
|
final PyFile file = getTestFile();
|
|
final PyClass c = file.findTopLevelClass("C");
|
|
assertNotNull(c);
|
|
final TypeEvalContext context = TypeEvalContext.codeInsightFallback(myFixture.getProject());
|
|
assertNotNull(c.getMetaClassType(context));
|
|
final PyClass d = file.findTopLevelClass("D");
|
|
assertNotNull(d);
|
|
assertNotNull(d.getMetaClassType(context));
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
// PY-18254
|
|
public void testFunctionTypeComment() {
|
|
final PyFile file = getTestFile();
|
|
final PyFunction func = file.findTopLevelFunction("func");
|
|
assertNotNull(func);
|
|
final String annotation = func.getTypeCommentAnnotation();
|
|
assertEquals("(str) -> int", annotation);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
// PY-18741
|
|
public void testParameterTypeComment() {
|
|
final PyFile file = getTestFile();
|
|
final PyFunction func = file.findTopLevelFunction("func");
|
|
assertNotNull(func);
|
|
final PyParameter[] parameters = func.getParameterList().getParameters();
|
|
assertSize(2, parameters);
|
|
final PyNamedParameter param = assertInstanceOf(parameters[0], PyNamedParameter.class);
|
|
final String annotation = param.getTypeCommentAnnotation();
|
|
assertEquals("int", annotation);
|
|
assertNotParsed(file);
|
|
|
|
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), file);
|
|
final PyType paramType = context.getType(param);
|
|
assertInstanceOf(paramType, PyClassType.class);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testTargetExpressionTypeComment() {
|
|
final PyFile file = getTestFile();
|
|
final PyTargetExpression target = file.findTopLevelAttribute("x");
|
|
assertNotNull(target);
|
|
|
|
final String annotation = target.getTypeCommentAnnotation();
|
|
assertEquals("int", annotation);
|
|
assertNotParsed(file);
|
|
|
|
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), file);
|
|
final PyType paramType = context.getType(target);
|
|
assertInstanceOf(paramType, PyClassType.class);
|
|
assertNotParsed(file);
|
|
}
|
|
|
|
public void testFullyQualifiedNamedTuple() {
|
|
doTestNamedTuple(
|
|
QualifiedName.fromDottedString("collections.namedtuple")
|
|
);
|
|
}
|
|
|
|
public void testFullyQualifiedNamedTupleWithAs() {
|
|
doTestNamedTuple(
|
|
QualifiedName.fromDottedString("C.namedtuple")
|
|
);
|
|
}
|
|
|
|
public void testImportedNamedTuple() {
|
|
doTestNamedTuple(
|
|
QualifiedName.fromComponents("namedtuple")
|
|
);
|
|
}
|
|
|
|
public void testImportedNamedTupleWithAs() {
|
|
doTestNamedTuple(
|
|
QualifiedName.fromComponents("NT")
|
|
);
|
|
}
|
|
|
|
public void testNamedTupleFieldsSequence() {
|
|
doTestNamedTupleArguments();
|
|
}
|
|
|
|
public void testNamedTupleNameReference() {
|
|
doTestNamedTupleArguments();
|
|
}
|
|
|
|
public void testNamedTupleFieldsReference() {
|
|
doTestNamedTupleArguments();
|
|
}
|
|
|
|
public void testNamedTupleNameChain() {
|
|
doTestNamedTupleArguments();
|
|
}
|
|
|
|
public void testNamedTupleFieldsChain() {
|
|
doTestNamedTupleArguments();
|
|
}
|
|
|
|
public void testImportedNamedTupleName() {
|
|
doTestUnsupportedNamedTuple();
|
|
}
|
|
|
|
public void testImportedNamedTupleFields() {
|
|
doTestUnsupportedNamedTuple();
|
|
}
|
|
|
|
private void doTestNamedTuple(@NotNull QualifiedName expectedCalleeName) {
|
|
doTestNamedTuple("name", Collections.singletonList("field"), expectedCalleeName);
|
|
}
|
|
|
|
private void doTestNamedTupleArguments() {
|
|
doTestNamedTuple("name", Arrays.asList("x", "y"), QualifiedName.fromComponents("namedtuple"));
|
|
}
|
|
|
|
private void doTestNamedTuple(@NotNull String expectedName,
|
|
@NotNull List<String> expectedFields,
|
|
@NotNull QualifiedName expectedCalleeName) {
|
|
final PyFile file = getTestFile();
|
|
|
|
final PyTargetExpression attribute = file.findTopLevelAttribute("nt");
|
|
assertNotNull(attribute);
|
|
|
|
final PyNamedTupleStub stub = attribute.getStub().getCustomStub(PyNamedTupleStub.class);
|
|
assertNotNull(stub);
|
|
assertEquals(expectedCalleeName, stub.getCalleeName());
|
|
|
|
final PyType typeFromStub = TypeEvalContext.codeInsightFallback(myFixture.getProject()).getType(attribute);
|
|
doTestNamedTuple(expectedName, expectedFields, typeFromStub);
|
|
assertNotParsed(file);
|
|
|
|
final FileASTNode astNode = file.getNode();
|
|
assertNotNull(astNode);
|
|
|
|
final PyType typeFromAst = TypeEvalContext.userInitiated(myFixture.getProject(), file).getType(attribute);
|
|
doTestNamedTuple(expectedName, expectedFields, typeFromAst);
|
|
}
|
|
|
|
private void doTestUnsupportedNamedTuple() {
|
|
final PyFile file = getTestFile();
|
|
|
|
final PyTargetExpression attribute = file.findTopLevelAttribute("nt");
|
|
assertNotNull(attribute);
|
|
|
|
final PyType typeFromStub = TypeEvalContext.codeInsightFallback(myFixture.getProject()).getType(attribute);
|
|
assertNull(typeFromStub);
|
|
assertNotParsed(file);
|
|
|
|
final FileASTNode astNode = file.getNode();
|
|
assertNotNull(astNode);
|
|
|
|
final PyType typeFromAst = TypeEvalContext.userInitiated(myFixture.getProject(), file).getType(attribute);
|
|
assertNull(typeFromAst);
|
|
}
|
|
|
|
private static void doTestNamedTuple(@NotNull String expectedName,
|
|
@NotNull List<String> expectedFields,
|
|
@Nullable PyType type) {
|
|
assertInstanceOf(type, PyNamedTupleType.class);
|
|
|
|
final PyNamedTupleType namedTupleType = (PyNamedTupleType)type;
|
|
|
|
assertEquals(expectedName, namedTupleType.getName());
|
|
assertEquals(expectedFields, namedTupleType.getElementNames());
|
|
}
|
|
}
|