// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;

import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
import com.jetbrains.python.fixture.PyCommonResolveTestCase;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.resolve.ImportedResolveResult;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.PyClassTypeImpl;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.pyi.PyiUtil;
import junit.framework.TestCase;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;

import java.util.function.Consumer;

public abstract class PyCommonResolveTest extends PyCommonResolveTestCase {

  @Override
  protected PsiElement doResolve() {
    final PsiReference ref = findReferenceByMarker();
    return ref.resolve();
  }

  private PsiReference findReferenceByMarker() {
    myFixture.configureByFile("resolve/" + getTestName(false) + ".py");
    return PyCommonResolveTestCase.findReferenceByMarker(myFixture.getFile());
  }

  protected PsiElement resolve() {
    PsiReference ref = configureByFile("resolve/" + getTestName(false) + ".py");
    //  if need be: PythonLanguageLevelPusher.setForcedLanguageLevel(project, LanguageLevel.PYTHON26);
    return ref.resolve();
  }

  private ResolveResult[] multiResolve() {
    PsiReference ref = findReferenceByMarker();
    assertInstanceOf(ref, PsiPolyVariantReference.class);
    return ((PsiPolyVariantReference)ref).multiResolve(false);
  }

  private <T extends PsiNamedElement> T assertResolvesTo(@Language("TEXT") @NotNull String text,
                                                         @NotNull Class<T> cls,
                                                         @NotNull String name) {
    final Ref<T> result = new Ref<>();

    runWithLanguageLevel(
      LanguageLevel.getLatest(),
      () -> {
        myFixture.configureByText(PythonFileType.INSTANCE, text);
        result.set(assertResolveResult(PyCommonResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve(), cls, name));
      }
    );

    return result.get();
  }

  public void testClass() {
    assertResolvesTo(PyClass.class, "Test");
  }

  public void testFunc() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyFunction.class);
  }

  public void testInitialization() {
    assertResolvesTo(
      """
        class Foo:
          pass
        Foo()
         <ref>""",
      PyClass.class,
      "Foo"
    );
  }

  public void testInitializationWithDunderInit() {
    assertResolvesTo(
      """
        class Foo:
          def __init__(self):
            pass
        Foo()
         <ref>""",
      PyClass.class,
      "Foo"
    );
  }

  // PY-17877
  public void testInitializationWithMetaclassDunderCall() {
    assertResolvesTo(
      """
        class MyMeta(type):
            def __call__(cls, p1, p2):
                pass

        class MyClass(metaclass=MyMeta):
            pass

        MyClass()
          <ref>""",
      PyClass.class,
      "MyClass"
    );
  }

  public void testInitializationWithDunderInitAndMetaclassDunderCall() {
    assertResolvesTo(
      """
        class MyMeta(type):
            def __call__(cls, p1, p2):
                pass

        class MyClass(metaclass=MyMeta):
            def __init__(self): pass

        MyClass()
          <ref>""",
      PyClass.class,
      "MyClass"
    );
  }

  // PY-17877, PY-41380
  public void testInitializationWithMetaclassSelfArgsKwargsDunderCall() {
    assertResolvesTo(
      """
        class MyMeta(type):
            def __call__(cls, *args, **kwargs):
                pass

        class MyClass(metaclass=MyMeta):
            pass

        MyClass()
          <ref>""",
      PyClass.class,
      "MyClass"
    );
  }

  public void testInitOrNewReturnsInitWhenNewIsFirst() {
    doTestInitOrNewReturnsInit();
  }

  public void testInitOrNewReturnsInitWhenNewIsLast() {
    doTestInitOrNewReturnsInit();
  }

  private void doTestInitOrNewReturnsInit() {
    myFixture.configureByFile("resolve/" + getTestName(false) + ".py");
    final PyClass pyClass = PsiTreeUtil.findChildOfType(myFixture.getFile(), PyClass.class);
    assertNotNull(pyClass);
    final PyFunction init = pyClass.findInitOrNew(false, TypeEvalContext.userInitiated(myFixture.getProject(), myFixture.getFile()));
    assertEquals(PyNames.INIT, init.getName());
  }

  public void testToConstructorInherited() {
    ResolveResult[] targets = multiResolve();
    assertEquals(1, targets.length); // to class, to init
    PsiElement elt;
    // class
    elt = targets[0].getElement();
    assertInstanceOf(elt, PyClass.class);
    assertEquals("Bar", ((PyClass)elt).getName());
  }

  // NOTE: maybe this test does not belong exactly here; still it's the best place currently.
  public void testComplexCallee() {
    PsiElement targetElement = resolve();
    PyExpression assigned = ((PyAssignmentStatement)targetElement.getContext()).getAssignedValue();
    assertInstanceOf(assigned, PyCallExpression.class);
    PsiElement callee = ((PyCallExpression)assigned).getCallee();
    assertInstanceOf(callee, PySubscriptionExpression.class);
  }

  public void testVar() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testDefaultInClass() {
    PsiElement targetElement = resolve();
    assertNotNull(targetElement);
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertEquals("FOO", ((PyTargetExpression)targetElement).getName());
  }

  public void testQualifiedFunc() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyFunction.class);
  }

  public void testQualifiedVar() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testQualifiedTarget() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testQualifiedFalseTarget() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testInnerFuncVar() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testTupleInComprh() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testForStatement() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testExceptClause() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testLookAhead() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testLookAheadCapped() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testTryExceptElse() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testGlobal() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testGlobalInNestedFunction() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(ScopeUtil.getScopeOwner(targetElement), PyFile.class);
  }

  public void testGlobalDefinedLocally() {
    final PsiElement element = resolve();
    assertInstanceOf(element, PyTargetExpression.class);
    final PsiElement parent = element.getParent();
    assertInstanceOf(parent, PyAssignmentStatement.class);
  }

  // PY-82115
  public void testGlobalDefinedLocally2() {
    PyTargetExpression target = assertResolvesTo(PyTargetExpression.class, "s");
    PyFunction function = assertInstanceOf(ScopeUtil.getScopeOwner(target), PyFunction.class);
    assertEquals("inner", function.getName());
  }

  // PY-82115
  public void testGlobalNotResolvedToLocalNameInOuterScope() {
    // resolves to itself
    PsiElement resolved = doResolve();
    PsiReference reference = findReferenceByMarker(myFixture.getFile());
    assertEquals(reference.getElement(), resolved);
  }

  public void testLambda() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyNamedParameter.class);
  }

  public void testLambdaParameterOutside() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testSuperField() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testFieldInCondition() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testMultipleFields() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testClassPeerMembers() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyFunction.class);
  }

  public void testTuple() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testMultiTarget() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testMultiTargetTuple() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertNotNull(PsiTreeUtil.getParentOfType(targetElement, PyAssignmentStatement.class)); // it's deep in a tuple
  }

  public void testWithStatement() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyWithItem.class);
  }

  public void testTupleInExcept() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertNotNull(PsiTreeUtil.getParentOfType(targetElement, PyExceptPart.class));
  }


  public void testDocStringClass() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyStringLiteralExpression.class);
    assertEquals("Docstring of class Foo", ((PyStringLiteralExpression)targetElement).getStringValue());
  }

  public void testDocStringInstance() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyStringLiteralExpression.class);
    assertEquals("Docstring of class Foo", ((PyStringLiteralExpression)targetElement).getStringValue());
  }

  public void testDocStringFunction() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyStringLiteralExpression.class);
    assertEquals("Docstring of function bar", ((PyStringLiteralExpression)targetElement).getStringValue());
  }

  public void testDocStringInvalid() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testFieldNotInInit() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testClassIsNotMemberOfItself() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testSuper() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyFunction.class);
    assertEquals("A", ((PyFunction)targetElement).getContainingClass().getName());
  }

  public void testSuperPy3k() {  // PY-1330
    runWithLanguageLevel(
      LanguageLevel.PYTHON34,
      () -> {
        final PyFunction pyFunction = assertResolvesTo(PyFunction.class, "foo");
        assertEquals("A", pyFunction.getContainingClass().getName());
      }
    );
  }

  public void testStackOverflow() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testProperty() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyFunction.class);
    assertEquals("set_full_name", ((PyFunction)targetElement).getName());
  }

  public void testLambdaWithParens() {  // PY-882
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyParameter.class);
  }

  public void testTextBasedResolve() {
    ResolveResult[] resolveResults = multiResolve();
    assertEquals(1, resolveResults.length);
    assertInstanceOf(resolveResults[0].getElement(), PyFunction.class);
  }

  public void testClassPrivateInClass() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testClassPrivateInMethod() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testClassPrivateInMethodNested() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testClassPrivateInherited() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
    assertInstanceOf(targetElement.getParent(), PyAssignmentStatement.class);
  }

  public void testClassPrivateOutsideClass() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testClassPrivateOutsideInstance() {
    PsiElement targetElement = resolve();
    assertNull(targetElement);
  }

  public void testClassNameEqualsMethodName() {
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyFunction.class);
  }

  public void testUnresolvedImport() {
    final ResolveResult[] results = multiResolve();
    assertEquals(1, results.length);
    assertInstanceOf(results[0], ImportedResolveResult.class);
    ImportedResolveResult result = (ImportedResolveResult)results[0];
    assertNull(result.getElement());
  }

  public void testIsInstance() {  // PY-1133
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyNamedParameter.class);
  }

  public void testListComprehension() { // PY-1143
    PsiElement targetElement = resolve();
    assertInstanceOf(targetElement, PyTargetExpression.class);
  }

  public void testSuperMetaClass() {
    assertResolvesTo(PyFunction.class, "foo");
  }

  //PY-28562
  public void testSuperMetaClassInheritsObject() {
    assertResolvesTo(PyFunction.class, "__getattribute__");
  }


  public void testSuperDunderClass() {  // PY-1190
    assertResolvesTo(PyFunction.class, "foo");
  }

  public void testSuperTwoClasses() {  // PY-2133
    final PyFunction pyFunction = assertResolvesTo(PyFunction.class, "my_call");
    assertEquals("Base2", pyFunction.getContainingClass().getName());
  }

  public void testLambdaDefaultParameter() {
    final PsiElement element = doResolve();
    assertInstanceOf(element, PyTargetExpression.class);
    assertInstanceOf(element.getParent(), PySetCompExpression.class);
  }

  public void testListAssignment() {
    final PsiElement element = doResolve();
    assertInstanceOf(element, PyTargetExpression.class);
  }

  public void testStarUnpacking() {  // PY-1459
    assertResolvesTo(LanguageLevel.PYTHON34, PyTargetExpression.class, "heads");
  }

  public void testStarUnpackingInLoop() {  // PY-1525
    assertResolvesTo(LanguageLevel.PYTHON34, PyTargetExpression.class, "bbb");
  }

  public void testBuiltinVsClassMember() {  // PY-1654
    final PyFunction pyFunction = assertResolvesTo(PyFunction.class, "eval");
    assertIsBuiltin(pyFunction);
  }

  public void testLambdaToClass() {  // PY-2182
    assertResolvesTo(PyClass.class, "TestTwo");
  }

  public void testImportInTryExcept() {  // PY-2197
    assertResolvesTo(PyFile.class, "sys.pyi");
  }

  public void testModuleToBuiltins() {
    final PsiElement element = doResolve();
    assertNull(element);
  }

  public void testWithParentheses() {
    assertResolvesTo(LanguageLevel.PYTHON27, PyTargetExpression.class, "MockClass1");
  }

  public void testPrivateInsideModule() {  // PY-2618
    assertResolvesTo(PyClass.class, "__VeryPrivate");
  }

  public void testRedeclaredInstanceVar() {  // PY-2740
    assertResolvesTo(PyFunction.class, "jobsDoneCount");
  }

  public void testNoResolveIntoGenerator() {  // PY-3030
    PyTargetExpression expr = assertResolvesTo(PyTargetExpression.class, "foo");
    assertEquals("foo = 1", expr.getParent().getText());
  }

  public void testResolveInGenerator() {
    assertResolvesTo(PyTargetExpression.class, "foo");
  }

  public void testNestedListComp() {  // PY-3068
    assertResolvesTo(PyTargetExpression.class, "yy");
  }

  public void testSuperclassResolveScope() {  // PY-3554
    assertResolvesTo(PyClass.class, "date", "datetime.pyi");
  }

  public void testDontResolveTargetToBuiltins() {  // PY-4256
    assertResolvesTo(PyTargetExpression.class, "str");
  }

  public void testKeywordArgument() {
    assertResolvesTo(PyNamedParameter.class, "bar");
  }

  public void testImplicitResolveInstanceAttribute() {
    ResolveResult[] resolveResults = multiResolve();
    assertEquals(1, resolveResults.length);
    final PsiElement psiElement = resolveResults[0].getElement();
    assertTrue(psiElement instanceof PyTargetExpression && "xyzzy".equals(((PyTargetExpression)psiElement).getName()));
  }

  public void testAttributeAssignedNearby() {
    assertResolvesTo(PyTargetExpression.class, "xyzzy");
  }

  public void testPreviousTarget() {
    PsiElement resolved = resolve();
    assertInstanceOf(resolved, PyTargetExpression.class);
    PyTargetExpression target = (PyTargetExpression)resolved;
    PyExpression value = target.findAssignedValue();
    assertInstanceOf(value, PyNumericLiteralExpression.class);
  }

  public void testMetaclass() {
    final PyFunction function = assertResolvesTo(PyFunction.class, "getStore");
    assertEquals("PluginMetaclass", function.getContainingClass().getName());
  }

  // PY-6083
  public void testLambdaParameterInDecorator() {
    assertResolvesTo(PyNamedParameter.class, "xx");
  }

  // PY-6435
  public void testLambdaParameterInDefaultValue() {
    assertResolvesTo(PyNamedParameter.class, "xx");
  }

  // PY-6540
  public void testClassRedefinedField() {
    assertResolvesTo(PyClass.class, "Foo");
  }

  public void testKWArg() {
    assertResolvesTo(PyClass.class, "timedelta");
  }

  public void testShadowingTargetExpression() {
    assertResolvesTo(PyTargetExpression.class, "lab");
  }

  public void testReferenceInDocstring() {
    assertResolvesTo(PyClass.class, "datetime");
  }

  // PY-9795
  public void testGoogleDocstringParamType() {
    runWithDocStringFormat(DocStringFormat.GOOGLE, () -> assertResolvesTo(PyClass.class, "datetime"));
  }

  // PY-9795
  public void testGoogleDocstringReturnType() {
    runWithDocStringFormat(DocStringFormat.GOOGLE, () -> assertResolvesTo(PyClass.class, "MyClass"));
  }

  // PY-16906
  public void testGoogleDocstringModuleAttribute() {
    runWithDocStringFormat(DocStringFormat.GOOGLE, () -> assertResolvesTo(PyTargetExpression.class, "module_level_variable1"));
  }

  // PY-7541
  public void testLoopToUpperReassignment() {
    final PsiReference ref = findReferenceByMarker();
    final PsiElement source = ref.getElement();
    final PsiElement target = ref.resolve();
    assertNotNull(target);
    assertNotSame(source, target);
    assertTrue(PyPsiUtils.isBefore(target, source));
  }

  // PY-7541
  public void testLoopToLowerReassignment() {
    final PsiReference ref = findReferenceByMarker();
    final PsiElement source = ref.getElement();
    final PsiElement target = ref.resolve();
    assertNotNull(target);
    assertSame(source, target);
  }

  // PY-7970
  public void testAugmentedAssignment() {
    assertResolvesTo(PyTargetExpression.class, "foo");
  }

  // PY-7970
  public void testAugmentedAfterAugmented() {
    final PsiReference ref = findReferenceByMarker();
    final PsiElement source = ref.getElement();
    final PsiElement resolved = ref.resolve();
    assertInstanceOf(resolved, PyReferenceExpression.class);
    assertNotSame(resolved, source);
    final PyReferenceExpression res = (PyReferenceExpression)resolved;
    assertNotNull(res);
    assertEquals("foo", res.getName());
    assertInstanceOf(res.getParent(), PyAugAssignmentStatement.class);
  }

  public void testGeneratorShadowing() {  // PY-8725
    assertResolvesTo(PyFunction.class, "_");
  }

  // PY-6805
  public void testAttributeDefinedInNew() {
    final PsiElement resolved = resolve();
    assertInstanceOf(resolved, PyTargetExpression.class);
    final PyTargetExpression target = (PyTargetExpression)resolved;
    assertEquals("foo", target.getName());
    final ScopeOwner owner = ScopeUtil.getScopeOwner(target);
    assertNotNull(owner);
    assertInstanceOf(owner, PyFunction.class);
    assertEquals("__new__", owner.getName());
  }

  public void testPreferInitForAttributes() {  // PY-9228
    PyTargetExpression xyzzy = assertResolvesTo(PyTargetExpression.class, "xyzzy");
    assertEquals("__init__", PsiTreeUtil.getParentOfType(xyzzy, PyFunction.class).getName());
  }

  // PY-11401
  public void testResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails() {
    assertResolvesTo(PyFunction.class, "foo");
  }

  // PY-15390
  public void testMatMul() {
    assertResolvesTo(PyFunction.class, "__matmul__");
  }

  // PY-15390
  public void testRMatMul() {
    assertResolvesTo(PyFunction.class, "__rmatmul__");
  }

  //PY-2748
  public void testFormatStringKWArgs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyNumericLiteralExpression.class);
    assertEquals(12, (long)((PyNumericLiteralExpression)target).getLongValue());
  }

  //PY-2748
  public void testFormatPositionalArgs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyReferenceExpression.class);
    assertEquals("string", target.getText());
  }

  //PY-2748
  public void testFormatArgsAndKWargs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
  }

  //PY-2748
  public void testFormatArgsAndKWargs1() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("keyword", ((PyStringLiteralExpression)target).getStringValue());
  }

  //PY-2748
  public void testFormatStringWithPackedDictAsArgument() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("\"f\"", target.getText());
  }

  //PY-2748
  public void testFormatStringWithPackedListAsArgument() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyNumericLiteralExpression.class);
    assertEquals("1", target.getText());
  }

  //PY-2748
  public void testFormatStringWithPackedTupleAsArgument() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("\"snd\"", target.getText());
  }

  //PY-2748
  public void testFormatStringWithRefAsArgument() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStarArgument.class);
  }


  //PY-2748
  public void testPercentPositionalArgs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
  }

  //PY-2748
  public void testPercentKeyWordArgs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyNumericLiteralExpression.class);
    assertNotNull(((PyNumericLiteralExpression)target).getLongValue());
    assertEquals(Long.valueOf(4181), ((PyNumericLiteralExpression)target).getLongValue());
  }

  public void testPercentStringKeyWordArgWithParentheses() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("s", ((PyStringLiteralExpression)target).getStringValue());
  }

  //PY-2748
  public void testPercentStringBinaryStatementArg() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("1", ((PyStringLiteralExpression)target).getStringValue());
  }

  //PY-2748
  public void testPercentStringArgWithRedundantParentheses() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyStringLiteralExpression.class);
    assertEquals("1", ((PyStringLiteralExpression)target).getStringValue());
  }

  //PY-2748
  public void testPercentStringWithRefAsArgument() {
    PsiElement target = resolve();
    assertEquals("tuple", target.getText());
  }

  //PY-2748
  public void testPercentStringWithOneStringArgument() {
    PsiElement target = resolve();
    assertEquals("hello", ((PyStringLiteralExpression)target).getStringValue());
  }

  //PY-2748
  public void testFormatStringPackedDictCall() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyKeywordArgument.class);
  }

  //PY-2748
  public void testPercentStringDictCall() {
    PsiElement target = resolve();
    assertEquals("hello", ((PyStringLiteralExpression)((PyKeywordArgument)target).getValueExpression()).getStringValue());
  }

  // PY-2748
  public void testPercentStringParenDictCall() {
    PsiElement target = resolve();
    assertEquals("hello", ((PyStringLiteralExpression)((PyKeywordArgument)target).getValueExpression()).getStringValue());
  }

  // PY-2748
  public void testPercentStringPosParenDictCall() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyCallExpression.class);
    assertEquals("dict()", target.getText());
  }

  // PY-2748
  public void testFormatStringWithPackedAndNonPackedArgs() {
    PsiElement target = resolve();
    assertInstanceOf(target, PyNumericLiteralExpression.class);
    assertEquals("2", target.getText());
  }

  public void testGlobalNotDefinedAtTopLevel() {
    assertResolvesTo(PyTargetExpression.class, "foo");
  }

  // PY-13734
  public void testImplicitDunderClass() {
    assertUnresolved();
  }

  public void testImplicitDunderDoc() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testImplicitDunderSizeOf() {
    assertUnresolved();
  }

  public void testImplicitUndeclaredClassAttr() {
    assertUnresolved();
  }

  public void testImplicitQualifiedClassAttr() {
    ResolveResult[] resolveResults = multiResolve();
    assertEquals(1, resolveResults.length);
    PyTargetExpression target = assertInstanceOf(resolveResults[0].getElement(), PyTargetExpression.class);
    assertEquals("CLASS_ATTR", target.getName());
    assertInstanceOf(ScopeUtil.getScopeOwner(target), PyClass.class);
  }

  // PY-13734
  public void testImplicitDunderClassNewStyleClass() {
    assertUnresolved();
  }

  public void testImplicitDunderDocNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testImplicitDunderSizeOfNewStyleClass() {
    assertUnresolved();
  }

  public void testImplicitUndeclaredClassAttrNewStyleClass() {
    assertUnresolved();
  }

  // PY-13734
  public void testImplicitDunderClassWithClassAttr() {
    assertUnresolved();
  }

  public void testImplicitDunderDocWithClassAttr() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testImplicitDunderSizeOfWithClassAttr() {
    assertUnresolved();
  }

  public void testImplicitClassAttr() {
    assertUnresolved();
  }

  // PY-13734
  public void testImplicitDunderClassWithClassAttrNewStyleClass() {
    assertUnresolved();
  }

  public void testImplicitDunderDocWithClassAttrNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testImplicitDunderSizeOfWithClassAttrNewStyleClass() {
    assertUnresolved();
  }

  public void testImplicitClassAttrNewStyleClass() {
    assertUnresolved();
  }

  // PY-13734
  public void testImplicitDunderClassWithInheritedClassAttr() {
    assertUnresolved();
  }

  public void testImplicitDunderDocWithInheritedClassAttr() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testImplicitDunderSizeOfWithInheritedClassAttr() {
    assertUnresolved();
  }

  public void testImplicitInheritedClassAttr() {
    assertUnresolved();
  }

  // PY-13734
  public void testInstanceDunderClass() {
    assertIsBuiltin(assertResolvesTo(PyFunction.class, PyNames.__CLASS__));
  }

  public void testInstanceDunderDoc() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testInstanceDunderSizeOf() {
    assertUnresolved();
  }

  public void testInstanceUndeclaredClassAttr() {
    assertUnresolved();
  }

  // PY-13734
  public void testInstanceDunderClassNewStyleClass() {
    assertIsBuiltin(assertResolvesTo(PyFunction.class, PyNames.__CLASS__));
  }

  public void testInstanceDunderDocNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);
    assertIsBuiltin(expression);
  }

  public void testInstanceDunderSizeOfNewStyleClass() {
    final PyFunction expression = assertResolvesTo(PyFunction.class, PyNames.SIZEOF);
    assertIsBuiltin(expression);
  }

  public void testInstanceUndeclaredClassAttrNewStyleClass() {
    assertUnresolved();
  }

  // PY-13734
  public void testInstanceDunderClassWithClassAttr() {
    assertIsBuiltin(assertResolvesTo(PyFunction.class, PyNames.__CLASS__));
  }

  public void testInstanceDunderDocWithClassAttr() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  public void testInstanceDunderSizeOfWithClassAttr() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.SIZEOF);

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  public void testInstanceClassAttr() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, "my_attr");

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  // PY-13734
  public void testInstanceDunderClassWithClassAttrNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  public void testInstanceDunderDocWithClassAttrNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.DOC);

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  public void testInstanceDunderSizeOfWithClassAttrNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.SIZEOF);

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  public void testInstanceClassAttrNewStyleClass() {
    final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, "my_attr");

    final PyClass cls = expression.getContainingClass();
    assertNotNull(cls);
    assertEquals("A", cls.getName());
  }

  // PY-13734
