package com.jetbrains.python;

import com.jetbrains.python.fixtures.PyLightFixtureTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
import com.jetbrains.python.psi.types.*;

/**
 * @author yole
 */
public class PyTypeTest extends PyLightFixtureTestCase {
  public void testTupleType() {
    PyClassType type = (PyClassType) doTest("t = ('a', 2)\nexpr = t[0]");
    assertEquals("str", type.getName());
  }

  public void testTupleAssignmentType() {
    PyClassType type = (PyClassType) doTest("t = ('a', 2)\n(expr, q) = t");
    assertEquals("str", type.getName());
  }

  public void testBinaryExprType() {
    PyClassType type = (PyClassType) doTest("expr = 1 + 2");
    assertEquals("int", type.getName());

    type = (PyClassType) doTest("expr = '1' + '2'");
    assertEquals("str", type.getName());

    type = (PyClassType) doTest("expr = '%s' % ('a')");
    assertEquals("str", type.getName());

    type = (PyClassType) doTest("expr = [1] + [2]");
    assertEquals("list", type.getName());
  }

  public void testUnaryExprType() {
    PyClassType type = (PyClassType) doTest("expr = -1");
    assertEquals("int", type.getName());
  }

  public void testTypeFromComment() {
    PyClassType type = (PyClassType) doTest("expr = ''.capitalize()");
    assertEquals("str", type.getName());
  }

  public void testUnionOfTuples() {
    PyTupleType type = (PyTupleType) doTest("def x():\n" +
                                            "  if True:\n" +
                                            "    return (1, 'a')\n" +
                                            "  else:\n" +
                                            "    return ('a', 1)\n" +
                                            "expr = x()");
    assertTrue(type.getElementType(0) instanceof PyUnionType);
    assertTrue(type.getElementType(1) instanceof PyUnionType);
  }

  public void testAugAssignment() {
    PyClassType type = (PyClassType) doTest("def x():\n" +
                                            "    count = 0\n" +
                                            "    count += 1\n" +
                                            "    return count\n" +
                                            "expr = x()");
    assertEquals("int", type.getName());
  }

  public void testSetComp() {
    PyClassType type = (PyClassType) doTest("expr = {i for i in range(3)}");
    assertEquals("set", type.getName());
  }

  public void testSet() {
    PyClassType type = (PyClassType) doTest("expr = {1, 2, 3}");
    assertEquals("set", type.getName());
    assertInstanceOf(type, PyCollectionType.class);
    final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.fast());
    assertEquals("int", elementType.getName());
  }

  public void testNone() {   // PY-1425
    PyType type = doTest("class C:\n" +
                         "    def __init__(self): self.foo = None\n" +
                         "expr = C().foo");
    assertNull(type);
  }

  public void testUnicodeLiteral() {  // PY-1427
    PyClassType type = (PyClassType) doTest("expr = u'foo'");
    assertEquals("unicode", type.getName());
  }

  // TODO uncomment when we have a mock SDK for Python 3.x
  public void _testBytesLiteral() {  // PY-1427
    PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON30);
    try {
      PyClassType type = (PyClassType) doTest("expr = b'foo'");
      assertEquals("bytes", type.getName());
    }
    finally {
      PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
    }
  }

  public void testPropertyType() {
    PyType type = doTest("class C:\n" +
                         "    x = property(lambda self: object(), None, None)\n" +
                         "expr = C.x");
    assertNull(type);
  }

  public void testIterationType() {
    PyClassType type = (PyClassType) doTest("for expr in [1, 2, 3]: pass");
    assertEquals("int", type.getName());
  }

  public void testSubscriptType() {
    PyClassType type = (PyClassType) doTest("l = [1, 2, 3]; expr = l[0]");
    assertEquals("int", type.getName());
  }

  private PyType doTest(final String text) {
    myFixture.configureByText(PythonFileType.INSTANCE, text);
    PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
    return expr.getType(TypeEvalContext.slow());
  }
}
  

@@ -4203,16 +4203,216 @@
 );%0A  %7D%0A%0A
+  public void testSliceType() %7B%0A    PyCollectionType type = (PyCollectionType) doTest(%22l = %5B1,2,3%5D; expr=l%5B0:1%5D%22);%0A    assertEquals(%22int%22, type.getElementType(TypeEvalContext.fast()).getName());%0A  %7D%0A%0A
   privat

test for type of slice