import sys

import pytest

import hello


def test_add_one():
    assert hello.add_one(41) == 42
    assert hello.add_one(-2) == -1  # the ambiguous-sentinel case


def test_add_one_rejects_non_int():
    with pytest.raises(TypeError):
        hello.add_one("41")


def test_add_one_overflow():
    with pytest.raises(OverflowError):
        hello.add_one(2**70)


def test_greet():
    assert hello.greet("Ada") == "Hello, Ada!"
    assert hello.greet("Ada", "Welcome") == "Welcome, Ada!"


@pytest.mark.parametrize("args", [(), ("a", "b", "c")])
def test_greet_arity(args):
    with pytest.raises(TypeError):
        hello.greet(*args)


def test_greet_rejects_non_str():
    with pytest.raises(TypeError):
        hello.greet(1)


def test_total():
    assert hello.total([1, 2, 3]) == 6
    assert hello.total(iter(range(10))) == 45
    assert hello.total([]) == 0


def test_total_propagates_iterator_errors():
    def boom():
        yield 1
        raise RuntimeError("from the iterator")

    with pytest.raises(RuntimeError, match="from the iterator"):
        hello.total(boom())


def test_total_rejects_non_int_items():
    with pytest.raises(TypeError):
        hello.total([1, "two", 3])


@pytest.mark.skipif(
    not getattr(sys, "_is_gil_enabled", lambda: True)(),
    reason="exact refcounts are not meaningful on free-threaded builds",
)
def test_no_reference_leak():
    arg = 12345678
    hello.add_one(arg)
    before = sys.getrefcount(arg)
    for _ in range(1000):
        hello.add_one(arg)
        hello.total([arg])
    assert sys.getrefcount(arg) == before
