"""Tests for sync s3fifo_cache decorator."""

from s3fifo import s3fifo_cache


class TestS3FIFOCacheDecorator:
    def test_basic_caching(self):
        call_count = 0

        @s3fifo_cache
        def add(x, y):
            nonlocal call_count
            call_count += 1
            return x + y

        assert add(1, 2) == 3
        assert add(1, 2) == 3
        assert call_count == 1

    def test_with_maxsize(self):
        call_count = 0

        @s3fifo_cache(maxsize=2)
        def square(x):
            nonlocal call_count
            call_count += 1
            return x * x

        assert square(2) == 4
        assert square(3) == 9
        assert square(2) == 4
        info = square.cache_info()
        assert info.hits >= 1

    def test_cache_info(self):
        @s3fifo_cache(maxsize=10)
        def f(x):
            return x

        f(1)
        f(2)
        f(1)
        info = f.cache_info()
        assert info.hits == 1
        assert info.misses == 2
        assert info.maxsize == 10
        assert info.currsize == 2

    def test_cache_clear(self):
        @s3fifo_cache(maxsize=10)
        def f(x):
            return x

        f(1)
        f(2)
        f.cache_clear()
        info = f.cache_info()
        assert info.hits == 0
        assert info.misses == 0
        assert info.currsize == 0

    def test_cache_parameters(self):
        @s3fifo_cache(
            maxsize=64,
            typed=True,
            small_size_ratio=0.2,
            ghost_size_ratio=0.5,
            move_to_main_threshold=3,
        )
        def f(x):
            return x

        params = f.cache_parameters()
        assert params["maxsize"] == 64
        assert params["typed"] is True
        assert params["small_size_ratio"] == 0.2
        assert params["ghost_size_ratio"] == 0.5
        assert params["move_to_main_threshold"] == 3

    def test_wrapped(self):
        def original(x):
            return x

        cached = s3fifo_cache(original)
        assert cached.__wrapped__ is original

    def test_maxsize_zero(self):
        call_count = 0

        @s3fifo_cache(maxsize=0)
        def f(x):
            nonlocal call_count
            call_count += 1
            return x

        f(1)
        f(1)
        assert call_count == 2
        info = f.cache_info()
        assert info.hits == 0
        assert info.misses == 2
        assert info.currsize == 0

    def test_typed(self):
        @s3fifo_cache(maxsize=10, typed=True)
        def f(x):
            return x

        f(3)
        f(3.0)
        info = f.cache_info()
        assert info.misses == 2

    def test_kwargs(self):
        call_count = 0

        @s3fifo_cache(maxsize=10)
        def f(x, y=10):
            nonlocal call_count
            call_count += 1
            return x + y

        assert f(1) == 11
        assert f(1, y=10) == 11
        # kwargs make a different key
        assert call_count == 2

    def test_preserves_docstring(self):
        @s3fifo_cache
        def f(x):
            """My docstring."""
            return x

        assert f.__doc__ == "My docstring."

    def test_preserves_name(self):
        @s3fifo_cache
        def my_func(x):
            return x

        assert my_func.__name__ == "my_func"
