# Performance and Benchmarking Tests

## Template Rendering Performance Tests

```python
import asyncio
import pytest
from jinja2_async_environment.environment import AsyncEnvironment
from jinja2_async_environment.loaders import AsyncDictLoader


class TestTemplateRenderingPerformance:
    @pytest.fixture
    def simple_templates(self):
        return {
            "simple.html": "<h1>Hello {{ name }}!</h1>",
            "complex.html": """
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ heading }}</h1>
    <ul>
    {% for item in items %}
        <li>{{ loop.index }}: {{ item.name }} - {{ item.value }}</li>
    {% endfor %}
    </ul>
    {% if show_footer %}
        <footer>{{ footer_text }}</footer>
    {% endif %}
</body>
</html>
            """,
            "macro_template.html": """
{% macro render_user(name, age) -%}
<div class="user">
    <h3>{{ name }}</h3>
    <p>Age: {{ age }}</p>
</div>
{%- endmacro %}
{{ render_user("Alice", 30) }}
{{ render_user("Bob", 25) }}
            """,
        }

    @pytest.mark.benchmark
    def test_render_simple_template_performance(self, benchmark, simple_templates):
        """Benchmark simple template rendering performance."""

        async def render_simple():
            env = AsyncEnvironment(
                loader=AsyncDictLoader(simple_templates), enable_async=True
            )
            template = await env.get_template_async("simple.html")
            return await template.render_async(name="World")

        def run_benchmark():
            return asyncio.run(render_simple())

        result = benchmark(run_benchmark)
        assert "Hello World!" in result

    @pytest.mark.benchmark
    def test_render_complex_template_performance(self, benchmark, simple_templates):
        """Benchmark complex template rendering performance."""
        complex_context = {
            "title": "Performance Test Page",
            "heading": "Benchmark Results",
            "items": [{"name": f"Item {i}", "value": f"Value {i}"} for i in range(100)],
            "show_footer": True,
            "footer_text": "Generated by jinja2-async-environment",
        }

        async def render_complex():
            env = AsyncEnvironment(
                loader=AsyncDictLoader(simple_templates), enable_async=True
            )
            template = await env.get_template_async("complex.html")
            return await template.render_async(**complex_context)

        def run_benchmark():
            return asyncio.run(render_complex())

        result = benchmark(run_benchmark)
        assert "Performance Test Page" in result

    @pytest.mark.benchmark
    def test_render_macro_template_performance(self, benchmark, simple_templates):
        """Benchmark macro template rendering performance."""

        async def render_macro():
            env = AsyncEnvironment(
                loader=AsyncDictLoader(simple_templates), enable_async=True
            )
            template = await env.get_template_async("macro_template.html")
            return await template.render_async()

        def run_benchmark():
            return asyncio.run(render_macro())

        result = benchmark(run_benchmark)
        assert "Alice" in result and "Bob" in result
```

## Template Compilation Performance Tests

```python
import pytest
from jinja2_async_environment.environment import AsyncEnvironment


class TestTemplateCompilationPerformance:
    @pytest.mark.benchmark
    def test_compile_simple_template_performance(self, benchmark):
        """Benchmark simple template compilation performance."""
        env = AsyncEnvironment()
        source = "<h1>Hello {{ name }}!</h1>"

        def compile_simple():
            return env._compile(source, "simple.html")

        result = benchmark(compile_simple)
        assert result is not None

    @pytest.mark.benchmark
    def test_compile_complex_template_performance(self, benchmark):
        """Benchmark complex template compilation performance."""
        env = AsyncEnvironment()
        source = """
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ heading }}</h1>
    <ul>
    {% for item in items %}
        <li>{{ loop.index }}: {{ item.name }} - {{ item.value }}</li>
    {% endfor %}
    </ul>
    {% if show_footer %}
        <footer>{{ footer_text }}</footer>
    {% endif %}
</body>
</html>
        """

        def compile_complex():
            return env._compile(source, "complex.html")

        result = benchmark(compile_complex)
        assert result is not None

    @pytest.mark.benchmark
    def test_compile_macro_template_performance(self, benchmark):
        """Benchmark macro template compilation performance."""
        env = AsyncEnvironment()
        source = """
{% macro render_user(name, age) -%}
<div class="user">
    <h3>{{ name }}</h3>
    <p>Age: {{ age }}</p>
</div>
{%- endmacro %}
{{ render_user("Alice", 30) }}
        """

        def compile_macro():
            return env._compile(source, "macro.html")

        result = benchmark(compile_macro)
        assert result is not None
```

## Loader Performance Tests

```python
import pytest
from jinja2_async_environment.environment import AsyncEnvironment
from jinja2_async_environment.loaders import (
    AsyncDictLoader,
    AsyncFileSystemLoader,
    AsyncFunctionLoader,
)


class TestLoaderPerformance:
    @pytest.fixture
    def dict_templates(self):
        return {
            "template1.html": "<h1>Template 1</h1>",
            "template2.html": "<h2>Template 2</h2>",
            "template3.html": "<p>Template 3</p>",
        }

    @pytest.mark.benchmark
    def test_dict_loader_get_template_performance(self, benchmark, dict_templates):
        """Benchmark DictLoader template loading performance."""
        env = AsyncEnvironment(loader=AsyncDictLoader(dict_templates))

        async def load_template():
            return await env.get_template_async("template1.html")

        def run_benchmark():
            return asyncio.run(load_template())

        result = benchmark(run_benchmark)
        assert result is not None

    @pytest.mark.benchmark
    def test_dict_loader_list_templates_performance(self, benchmark, dict_templates):
        """Benchmark DictLoader template listing performance."""
        loader = AsyncDictLoader(dict_templates)

        async def list_templates():
            return await loader.list_templates_async()

        def run_benchmark():
            return asyncio.run(list_templates())

        result = benchmark(run_benchmark)
        assert len(result) == 3

    @pytest.mark.benchmark
    def test_function_loader_performance(self, benchmark):
        """Benchmark FunctionLoader performance."""

        def load_func(name):
            templates = {
                "template1.html": "<h1>Template 1</h1>",
                "template2.html": "<h2>Template 2</h2>",
            }
            return templates.get(name)

        loader = AsyncFunctionLoader(load_func)
        env = AsyncEnvironment(loader=loader)

        async def load_template():
            return await env.get_template_async("template1.html")

        def run_benchmark():
            return asyncio.run(load_template())

        result = benchmark(run_benchmark)
        assert result is not None
```

## Concurrency Performance Tests

```python
import asyncio
import pytest
from jinja2_async_environment.environment import AsyncEnvironment
from jinja2_async_environment.loaders import AsyncDictLoader


class TestConcurrencyPerformance:
    @pytest.fixture
    def templates(self):
        return {"template.html": "<h1>Hello {{ name }}! Request #{{ request_id }}</h1>"}

    @pytest.mark.benchmark
    def test_concurrent_template_rendering_performance(self, benchmark, templates):
        """Benchmark concurrent template rendering performance."""

        async def render_concurrent():
            env = AsyncEnvironment(loader=AsyncDictLoader(templates), enable_async=True)

            # Render 10 templates concurrently
            tasks = []
            for i in range(10):
                task = asyncio.create_task(env.get_template_async("template.html"))
                tasks.append(task)

            templates_list = await asyncio.gather(*tasks)

            # Render each template with different context
            render_tasks = []
            for i, template in enumerate(templates_list):
                task = asyncio.create_task(
                    template.render_async(name="World", request_id=i)
                )
                render_tasks.append(task)

            results = await asyncio.gather(*render_tasks)
            return results

        def run_benchmark():
            return asyncio.run(render_concurrent())

        results = benchmark(run_benchmark)
        assert len(results) == 10
        assert all("Hello World!" in result for result in results)

    @pytest.mark.benchmark
    def test_high_concurrency_template_loading_performance(self, benchmark, templates):
        """Benchmark high-concurrency template loading performance."""
        env = AsyncEnvironment(loader=AsyncDictLoader(templates))

        async def load_concurrent():
            # Load the same template 100 times concurrently
            tasks = []
            for _ in range(100):
                task = asyncio.create_task(env.get_template_async("template.html"))
                tasks.append(task)

            results = await asyncio.gather(*tasks)
            return results

        def run_benchmark():
            return asyncio.run(load_concurrent())

        results = benchmark(run_benchmark)
        assert len(results) == 100
```

## Memory Usage Tests

```python
import gc
import pytest
from jinja2_async_environment.environment import AsyncEnvironment
from jinja2_async_environment.loaders import AsyncDictLoader


class TestMemoryUsage:
    @pytest.fixture
    def large_template_set(self):
        """Create a large set of templates for memory testing."""
        templates = {}
        for i in range(1000):
            templates[f"template_{i}.html"] = (
                f"<h1>Template {i}</h1><p>{'x' * 1000}</p>"
            )
        return templates

    def test_template_cache_memory_usage(self, large_template_set):
        """Test memory usage of template caching."""
        # Get initial memory usage
        gc.collect()
        initial_objects = len(gc.get_objects())

        env = AsyncEnvironment(loader=AsyncDictLoader(large_template_set))

        # Load many templates to populate cache
        import asyncio

        async def load_templates():
            for i in range(100):
                await env.get_template_async(f"template_{i}.html")

        asyncio.run(load_templates())

        # Get memory usage after loading
        gc.collect()
        after_loading_objects = len(gc.get_objects())

        # The increase should be reasonable
        object_increase = after_loading_objects - initial_objects
        assert object_increase < 10000, (
            f"Object count increased by {object_increase}, which is too high"
        )

    def test_compilation_cache_memory_usage(self):
        """Test memory usage of compilation caching."""
        # Get initial memory usage
        gc.collect()
        initial_objects = len(gc.get_objects())

        env = AsyncEnvironment()

        # Compile many templates
        for i in range(1000):
            source = f"<h1>Template {i}</h1><p>{'x' * 100}</p>"
            env._compile(source, f"template_{i}.html")

        # Get memory usage after compilation
        gc.collect()
        after_compilation_objects = len(gc.get_objects())

        # The increase should be reasonable
        object_increase = after_compilation_objects - initial_objects
        assert object_increase < 50000, (
            f"Object count increased by {object_increase}, which is too high"
        )
```
