122 lines
3.4 KiB
Python
122 lines
3.4 KiB
Python
|
|
import subprocess
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from rein_openweights.tools import (
|
||
|
|
ToolPolicyError,
|
||
|
|
call_tool,
|
||
|
|
edit_file,
|
||
|
|
git_add_commit,
|
||
|
|
git_diff,
|
||
|
|
git_log,
|
||
|
|
git_status,
|
||
|
|
glob_files,
|
||
|
|
grep_files,
|
||
|
|
openai_tool_schemas,
|
||
|
|
read_file,
|
||
|
|
write_file,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _init_repo(tmp_path):
|
||
|
|
subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True)
|
||
|
|
subprocess.run(["git", "config", "user.email", "t@example.com"], cwd=tmp_path, check=True)
|
||
|
|
subprocess.run(["git", "config", "user.name", "t"], cwd=tmp_path, check=True)
|
||
|
|
subprocess.run(["git", "commit", "-q", "--allow-empty", "-m", "init"], cwd=tmp_path, check=True)
|
||
|
|
return tmp_path
|
||
|
|
|
||
|
|
|
||
|
|
def test_write_then_read_file(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello")
|
||
|
|
assert read_file(repo, "a.txt") == "hello"
|
||
|
|
|
||
|
|
|
||
|
|
def test_edit_file_replaces_first_occurrence(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "foo foo")
|
||
|
|
edit_file(repo, "a.txt", "foo", "bar")
|
||
|
|
assert read_file(repo, "a.txt") == "bar foo"
|
||
|
|
|
||
|
|
|
||
|
|
def test_edit_file_missing_old_raises(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello")
|
||
|
|
with pytest.raises(ToolPolicyError, match="old string not found"):
|
||
|
|
edit_file(repo, "a.txt", "nope", "x")
|
||
|
|
|
||
|
|
|
||
|
|
def test_path_traversal_is_blocked(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
with pytest.raises(ToolPolicyError, match="escapes repo root"):
|
||
|
|
read_file(repo, "../outside.txt")
|
||
|
|
|
||
|
|
|
||
|
|
def test_glob_files(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "src/a.py", "1")
|
||
|
|
write_file(repo, "src/b.py", "2")
|
||
|
|
write_file(repo, "src/c.txt", "3")
|
||
|
|
result = glob_files(repo, "**/*.py")
|
||
|
|
assert "src/a.py" in result
|
||
|
|
assert "src/b.py" in result
|
||
|
|
assert "src/c.txt" not in result
|
||
|
|
|
||
|
|
|
||
|
|
def test_grep_files(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello world\nneedle here\n")
|
||
|
|
result = grep_files(repo, "needle")
|
||
|
|
assert "a.txt:2:needle here" in result
|
||
|
|
|
||
|
|
|
||
|
|
def test_grep_files_no_matches(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello")
|
||
|
|
assert grep_files(repo, "zzz") == "(no matches)"
|
||
|
|
|
||
|
|
|
||
|
|
def test_git_status_diff_log_and_commit(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello")
|
||
|
|
assert "a.txt" in git_status(repo)
|
||
|
|
git_add_commit(repo, "add a.txt")
|
||
|
|
assert git_status(repo) == "(clean)"
|
||
|
|
assert "add a.txt" in git_log(repo)
|
||
|
|
|
||
|
|
|
||
|
|
def test_git_diff_after_edit(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
write_file(repo, "a.txt", "hello")
|
||
|
|
git_add_commit(repo, "add a.txt")
|
||
|
|
edit_file(repo, "a.txt", "hello", "goodbye")
|
||
|
|
assert "goodbye" in git_diff(repo)
|
||
|
|
|
||
|
|
|
||
|
|
def test_call_tool_dispatches_by_name(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
call_tool(repo, "write_file", {"path": "a.txt", "content": "x"})
|
||
|
|
assert read_file(repo, "a.txt") == "x"
|
||
|
|
|
||
|
|
|
||
|
|
def test_call_tool_unknown_name_raises(tmp_path):
|
||
|
|
repo = _init_repo(tmp_path)
|
||
|
|
with pytest.raises(ToolPolicyError, match="unknown tool"):
|
||
|
|
call_tool(repo, "delete_everything", {})
|
||
|
|
|
||
|
|
|
||
|
|
def test_openai_tool_schemas_cover_all_tools():
|
||
|
|
schemas = openai_tool_schemas()
|
||
|
|
names = {s["function"]["name"] for s in schemas}
|
||
|
|
assert names == {
|
||
|
|
"read_file",
|
||
|
|
"write_file",
|
||
|
|
"edit_file",
|
||
|
|
"glob_files",
|
||
|
|
"grep_files",
|
||
|
|
"git_status",
|
||
|
|
"git_diff",
|
||
|
|
"git_log",
|
||
|
|
"git_add_commit",
|
||
|
|
}
|