import pytest pytest.importorskip("claude_agent_sdk") from mirage import MountMode, RAMResource, Workspace # noqa: E402 from mirage.agents.claude_agent_sdk.server import _MirageTools # noqa: E402 @pytest.fixture def workspace(): return Workspace({"/": RAMResource()}, mode=MountMode.WRITE) @pytest.fixture def tools(workspace): return _MirageTools(workspace) @pytest.mark.asyncio async def test_execute_command_echo(tools): result = await tools.execute_command({"command": "echo hello"}) assert "hello" in result["content"][0]["text"] assert result.get("is_error") is not True @pytest.mark.asyncio async def test_execute_command_pipe(tools, workspace): await workspace.ops.write("/pipe.txt", b"aaa\nbbb\naaa\n") result = await tools.execute_command( {"command": "cat /pipe.txt | sort | uniq | wc -l"}) assert "2" in result["content"][0]["text"] @pytest.mark.asyncio async def test_read_file(tools, workspace): await workspace.ops.write("/hello.txt", b"line1\nline2\nline3\n") result = await tools.read({"path": "/hello.txt"}) text = result["content"][0]["text"] assert "line1" in text assert "line2" in text assert result.get("is_error") is not True @pytest.mark.asyncio async def test_read_file_with_offset_and_limit(tools, workspace): await workspace.ops.write("/multi.txt", b"a\nb\nc\nd\ne\n") result = await tools.read({"path": "/multi.txt", "offset": 1, "limit": 2}) text = result["content"][0]["text"] assert "b" in text assert "c" in text assert "a" not in text assert "d" not in text @pytest.mark.asyncio async def test_read_file_not_found(tools): result = await tools.read({"path": "/nonexistent.txt"}) assert result["is_error"] is True assert "not found" in result["content"][0]["text"] @pytest.mark.asyncio async def test_write_file(tools, workspace): result = await tools.write({"path": "/new.txt", "content": "hello world"}) assert result.get("is_error") is not True data = await workspace.ops.read("/new.txt") assert data == b"hello world" @pytest.mark.asyncio async def test_write_file_already_exists(tools, workspace): await workspace.ops.write("/exists.txt", b"first") result = await tools.write({"path": "/exists.txt", "content": "second"}) assert result["is_error"] is True assert "already exists" in result["content"][0]["text"] @pytest.mark.asyncio async def test_edit_file(tools, workspace): await workspace.ops.write("/edit.txt", b"foo bar baz") result = await tools.edit({ "path": "/edit.txt", "old_string": "bar", "new_string": "qux" }) assert result.get("is_error") is not True data = await workspace.ops.read("/edit.txt") assert data == b"foo qux baz" @pytest.mark.asyncio async def test_edit_file_not_found(tools): result = await tools.edit({ "path": "/missing.txt", "old_string": "x", "new_string": "y" }) assert result["is_error"] is True assert "not found" in result["content"][0]["text"] @pytest.mark.asyncio async def test_edit_string_not_found(tools, workspace): await workspace.ops.write("/nostr.txt", b"hello world") result = await tools.edit({ "path": "/nostr.txt", "old_string": "xyz", "new_string": "abc" }) assert result["is_error"] is True assert "not found" in result["content"][0]["text"] @pytest.mark.asyncio async def test_edit_multiple_occurrences_without_replace_all(tools, workspace): await workspace.ops.write("/multi.txt", b"aa bb aa") result = await tools.edit({ "path": "/multi.txt", "old_string": "aa", "new_string": "cc" }) assert result["is_error"] is True assert "replace_all" in result["content"][0]["text"] @pytest.mark.asyncio async def test_edit_replace_all(tools, workspace): await workspace.ops.write("/all.txt", b"aa bb aa") result = await tools.edit({ "path": "/all.txt", "old_string": "aa", "new_string": "cc", "replace_all": True }) assert result.get("is_error") is not True data = await workspace.ops.read("/all.txt") assert data == b"cc bb cc" @pytest.mark.asyncio async def test_write_creates_parent_dirs(tools, workspace): result = await tools.write({ "path": "/nested/deep/file.txt", "content": "hi" }) assert result.get("is_error") is not True data = await workspace.ops.read("/nested/deep/file.txt") assert data == b"hi" @pytest.mark.asyncio async def test_ls(tools, workspace): await tools.write({"path": "/dir/a.txt", "content": "a"}) await tools.write({"path": "/dir/b.txt", "content": "b"}) result = await tools.ls({"path": "/dir"}) text = result["content"][0]["text"] assert "a.txt" in text assert "b.txt" in text @pytest.mark.asyncio async def test_grep(tools, workspace): await workspace.ops.write("/search.txt", b"hello world\ngoodbye world\nhello again\n") result = await tools.grep({"pattern": "hello", "path": "/"}) text = result["content"][0]["text"] assert "hello" in text