"""Unit tests for code_exec tool."""

import pytest

from navi.tools.code_exec import CodeExecTool


class TestCodeExecTool:
    @pytest.fixture
    def tool(self):
        return CodeExecTool()

    async def test_hello_world(self, tool):
        result = await tool.execute({"code": "print('hello')"})
        assert result.success
        assert "hello" in result.output

    async def test_math(self, tool):
        result = await tool.execute({"code": "print(2 + 3)"})
        assert result.success
        assert "5" in result.output

    async def test_stderr(self, tool):
        result = await tool.execute({"code": "import sys; print('err', file=sys.stderr)"})
        # stderr is captured but the tool may or may not consider it an error
        assert "err" in (result.output or result.error or "")

    async def test_syntax_error(self, tool):
        result = await tool.execute({"code": "print("})
        assert not result.success

    async def test_metadata_carries_returncode_and_language(self, tool):
        result = await tool.execute({"code": "print('hi')"})
        assert result.success
        assert result.metadata["returncode"] == 0
        assert result.metadata["language"] == "python"

    async def test_timeout_param_clamped_to_max(self, tool):
        # 99999 -> clamped to _MAX_TIMEOUT (300). Fast code still succeeds; we
        # only assert the clamp path doesn't error and metadata is well-formed.
        result = await tool.execute({"code": "print('ok')", "timeout": 99999})
        assert result.success
        assert result.metadata["language"] == "python"

    async def test_timeout_param_triggers_timeout(self, tool):
        result = await tool.execute({"code": "import time; time.sleep(5)", "timeout": 1})
        assert not result.success
        assert result.error == "timeout"
        assert "timed out after 1s" in result.output
        assert result.metadata["language"] == "python"
        assert result.metadata["timeout"] == 1
