# Test cases for tuples (compile and run)

[case testTuple]
from typing import List, Optional, Tuple
from typing import Tuple
def f(x: Tuple[int, int]) -> Tuple[int,int]:
    return x

def lurr(x: List[Optional[Tuple[int, str]]]) -> object:
    return x[0]

def asdf(x: Tuple[int, str]) -> None:
    pass
[file driver.py]
from testutil import assertRaises
from native import f, lurr, asdf

assert f((1,2)) == (1, 2)
assert lurr([(1, '2')]) == (1, '2')

with assertRaises(TypeError):
    print(lurr([(1, 2)]))

with assertRaises(TypeError):
    asdf((1, 2))

[case testTupleGet]
from typing import Tuple
def f(x: Tuple[Tuple[int, bool], int]) -> int:
    return x[0][0]
[file driver.py]
from native import f
print(f(((1,True),2)))
big_number = pow(2, 80)
print(f(((big_number,True),2)))
[out]
1
1208925819614629174706176

[case testSequenceTupleArg]
from typing import Tuple
def f(x: Tuple[int, ...]) -> int:
    return x[1]
[file driver.py]
from native import f
print(f((1,2,3,4)))
[out]
2

[case testTupleAttr]
from typing import Tuple
class C:
    b: Tuple[Tuple[Tuple[int, int], int], int, str, object]
    c: Tuple[()]
def f() -> None:
    c = C()
    c.b = (((1, 2), 2), 1, 'hi', 'hi2')
    print(c.b)

def g() -> None:
    try:
        h()
    except Exception:
        print('caught the exception')

def h() -> Tuple[Tuple[Tuple[int, int], int], int, str, object]:
    raise Exception('Intentional exception')
[file driver.py]
from native import f, g, C
f()
g()
assert not hasattr(C(), 'c')
[out]
(((1, 2), 2), 1, 'hi', 'hi2')
caught the exception

[case testNamedTupleAttributeRun]
from typing import NamedTuple

NT = NamedTuple('NT', [('x', int), ('y', int)])

def f(nt: NT) -> int:
    if nt.x > nt.y:
        return nt.x
    return nt.y

nt = NT(1, 2)
[file driver.py]
from native import NT, nt, f

assert f(nt) == 2
assert f(NT(3, 2)) == 3

class Sub(NT):
    pass
assert f(Sub(3, 2)) == 3

-- Ref: https://github.com/mypyc/mypyc/issues/924
[case testNamedTupleClassSyntax]
from typing import Dict, List, NamedTuple, Optional, Tuple, Union
from typing_extensions import final

class FuncIR: pass

StealsDescription = Union[bool, List[bool]]

class Record(NamedTuple):
    st_mtime: float
    st_size: int
    is_borrowed: bool
    hash: str
    python_path: Tuple[str, ...]
    type: 'ClassIR'
    method: FuncIR
    shadow_method: Optional[FuncIR]
    classes: Dict[str, 'ClassIR']
    steals: StealsDescription
    ordering: Optional[List[int]]
    extra_int_constants: List[Tuple[int]]

# Make sure mypyc loads the annotation string for this forward reference.
# Ref: https://github.com/mypyc/mypyc/issues/938
class ClassIR: pass

# Ref: https://github.com/mypyc/mypyc/issues/927
@final
class Inextensible(NamedTuple):
    x: int

[file driver.py]
from typing import ForwardRef, Optional
from native import ClassIR, FuncIR, Record

assert Record.__annotations__ == {
    'st_mtime': float,
    'st_size': int,
    'is_borrowed': bool,
    'hash': str,
    'python_path': tuple,
    'type': ForwardRef('ClassIR'),
    'method': FuncIR,
    'shadow_method': type,
    'classes': dict,
    'steals': type,
    'ordering': type,
    'extra_int_constants': list,
}, Record.__annotations__

[case testTupleOps]
from typing import Tuple, List, Any, Optional
from typing_extensions import Final

def f() -> Tuple[()]:
    return ()

def test_empty_tuple() -> None:
    assert f() == ()

def f2() -> Any:
    return ()

def test_empty_tuple_with_any_type():
    assert f2() == ()

def f3() -> int:
    x = (False, 1)
    return x[1]

def test_new_tuple() -> None:
    assert f3() == 1

def f4(y: int) -> int:
    x = (False, y)
    return x[1]

def test_new_tuple_boxed_int() -> None:
    big_number = 1208925819614629174706176
    assert f4(big_number) == big_number

def f5(x: List[int]) -> int:
    return tuple(x)[1]

def test_sequence_tuple() -> None:
    assert f5([1,2,3,4]) == 2

def f6(x: List[int]) -> int:
    return len(tuple(x))

def test_sequence_tuple_len() -> None:
    assert f6([1,2,3,4]) == 4

def f7(x: List[Tuple[int, int]]) -> int:
    a, b = x[0]
    return a + b

def test_unbox_tuple() -> None:
    assert f7([(5, 6)]) == 11

# Test that order is irrelevant to unions. Really I only care that this builds.

class A:
    pass

def lol() -> A:
    return A()

def foo(x: bool, y: bool) -> Tuple[Optional[A], bool]:
    z = lol()

    return None if y else z, x

def test_slicing() -> None:
    # Use dummy adds to avoid constant folding
    zero = int()
    two = zero + 2
    s: Tuple[str, ...] = ("f", "o", "o", "b", "a", "r")
    assert s[two:] == ("o", "b", "a", "r")
    assert s[:two] == ("f", "o")
    assert s[two:-two] == ("o", "b")
    assert s[two:two] == ()
    assert s[two:two + 1] == ("o",)
    assert s[-two:] == ("a", "r")
    assert s[:-two] == ("f", "o", "o", "b")
    assert s[:] == ("f", "o", "o", "b", "a", "r")
    assert s[two:333] == ("o", "b", "a", "r")
    assert s[333:two] == ()
    assert s[two:-333] == ()
    assert s[-333:two] == ("f", "o")
    long_int: int = 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000
    assert s[1:long_int] == ("o", "o", "b", "a", "r")
    assert s[long_int:] == ()
    assert s[-long_int:-1] == ("f", "o", "o", "b", "a")

def f8(val: int) -> bool:
    return val % 2 == 0

def test_sequence_generator() -> None:
    source_list = [1, 2, 3]
    a = tuple(f8(x) for x in source_list)
    assert a == (False, True, False)

    source_tuple: Tuple[int, ...] = (1, 2, 3)
    a = tuple(f8(x) for x in source_tuple)
    assert a == (False, True, False)

    source_fixed_length_tuple = (1, 2, 3, 4)
    a = tuple(f8(x) for x in source_fixed_length_tuple)
    assert a == (False, True, False, True)

    source_str = 'abbc'
    b = tuple('s:' + x for x in source_str)
    assert b == ('s:a', 's:b', 's:b', 's:c')

TUPLE: Final[Tuple[str, ...]] = ('x', 'y')

def test_final_boxed_tuple() -> None:
    t = TUPLE
    assert t == ('x', 'y')
