vibe/tests/tools/test_bash.py
Mathias Gesbert d33db9fff8 2.0.0
Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Clément Drouin <clement.drouin@mistral.ai>
Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai>
Co-Authored-By: Clément Siriex <clement.sirieix@mistral.ai>
Co-Authored-By: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai>
Co-Authored-By: Thaddee Tyl <thaddee.tyl@gmail.com>
Co-Authored-By: David Brochart <david.brochart@gmail.com>
Co-Authored-By: Joseph Guhlin <joseph.guhlin@gmail.com>
Co-Authored-By: Thomas Kenbeek <thomaskenbeek@gmail.com>
Co-Authored-By: Remenby31 <baptiste.cruvellier31@gmail.com>
2026-01-27 16:44:55 +01:00

91 lines
2.9 KiB
Python
Raw Blame History

from __future__ import annotations
import pytest
from tests.mock.utils import collect_result
from vibe.core.tools.base import BaseToolState, ToolError, ToolPermission
from vibe.core.tools.builtins.bash import Bash, BashArgs, BashToolConfig
@pytest.fixture
def bash(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
config = BashToolConfig()
return Bash(config=config, state=BaseToolState())
@pytest.mark.asyncio
async def test_runs_echo_successfully(bash):
result = await collect_result(bash.run(BashArgs(command="echo hello")))
assert result.returncode == 0
assert result.stdout == "hello\n"
assert result.stderr == ""
@pytest.mark.asyncio
async def test_fails_cat_command_with_missing_file(bash):
with pytest.raises(ToolError) as err:
await collect_result(bash.run(BashArgs(command="cat missing_file.txt")))
message = str(err.value)
assert "Command failed" in message
assert "Return code: 1" in message
assert "No such file or directory" in message
@pytest.mark.asyncio
async def test_uses_effective_workdir(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
config = BashToolConfig()
bash_tool = Bash(config=config, state=BaseToolState())
result = await collect_result(bash_tool.run(BashArgs(command="pwd")))
assert result.stdout.strip() == str(tmp_path)
@pytest.mark.asyncio
async def test_handles_timeout(bash):
with pytest.raises(ToolError) as err:
await collect_result(bash.run(BashArgs(command="sleep 2", timeout=1)))
assert "Command timed out after 1s" in str(err.value)
@pytest.mark.asyncio
async def test_truncates_output_to_max_bytes(bash):
config = BashToolConfig(max_output_bytes=5)
bash_tool = Bash(config=config, state=BaseToolState())
result = await collect_result(
bash_tool.run(BashArgs(command="printf 'abcdefghij'"))
)
assert result.stdout == "abcde"
assert result.stderr == ""
assert result.returncode == 0
@pytest.mark.asyncio
async def test_decodes_non_utf8_bytes(bash):
result = await collect_result(bash.run(BashArgs(command="printf '\\xff\\xfe'")))
# accept both possible encodings, as some shells emit escaped bytes as literal strings
assert result.stdout in {"<EFBFBD><EFBFBD>", "\xff\xfe", r"\xff\xfe"}
assert result.stderr == ""
def test_check_allowlist_denylist():
config = BashToolConfig(allowlist=["echo", "pwd"], denylist=["rm"])
bash_tool = Bash(config=config, state=BaseToolState())
allowlisted = bash_tool.check_allowlist_denylist(BashArgs(command="echo hi"))
denylisted = bash_tool.check_allowlist_denylist(BashArgs(command="rm -rf /tmp"))
mixed = bash_tool.check_allowlist_denylist(BashArgs(command="pwd && whoami"))
empty = bash_tool.check_allowlist_denylist(BashArgs(command=""))
assert allowlisted is ToolPermission.ALWAYS
assert denylisted is ToolPermission.NEVER
assert mixed is None
assert empty is None