import os
import pytest
from windows_mcp.filesystem.service import (
read_file,
write_file,
copy_path,
move_path,
delete_path,
list_directory,
search_files,
get_file_info,
)
class TestReadFile:
def test_read_entire_file(self, tmp_path):
f = tmp_path / "hello.txt"
f.write_text("hello world", encoding="utf-8")
result = read_file(str(f))
assert "hello world" in result
def test_read_with_offset_and_limit(self, tmp_path):
f = tmp_path / "lines.txt"
f.write_text("line1\nline2\nline3\nline4\n", encoding="utf-8")
result = read_file(str(f), offset=2, limit=2)
assert "line2" in result
assert "line3" in result
assert "line4" not in result
def test_read_nonexistent(self, tmp_path):
result = read_file(str(tmp_path / "nope.txt"))
assert "Error: File not found" in result
def test_read_directory_path(self, tmp_path):
result = read_file(str(tmp_path))
assert "Error: Path is not a file" in result
class TestWriteFile:
def test_write_new_file(self, tmp_path):
f = tmp_path / "out.txt"
result = write_file(str(f), "content")
assert "Written to" in result
assert f.read_text(encoding="utf-8") == "content"
def test_append_to_file(self, tmp_path):
f = tmp_path / "out.txt"
f.write_text("first", encoding="utf-8")
write_file(str(f), " second", append=True)
assert f.read_text(encoding="utf-8") == "first second"
def test_creates_parent_dirs(self, tmp_path):
f = tmp_path / "a" / "b" / "c.txt"
result = write_file(str(f), "deep")
assert "Written to" in result
assert f.read_text(encoding="utf-8") == "deep"
class TestCopyPath:
def test_copy_file(self, tmp_path):
src = tmp_path / "src.txt"
src.write_text("data", encoding="utf-8")
dst = tmp_path / "dst.txt"
result = copy_path(str(src), str(dst))
assert "Copied file" in result
assert dst.read_text(encoding="utf-8") == "data"
def test_copy_directory(self, tmp_path):
src = tmp_path / "srcdir"
src.mkdir()
(src / "file.txt").write_text("inside", encoding="utf-8")
dst = tmp_path / "dstdir"
result = copy_path(str(src), str(dst))
assert "Copied directory" in result
assert (dst / "file.txt").read_text(encoding="utf-8") == "inside"
def test_copy_source_not_found(self, tmp_path):
result = copy_path(str(tmp_path / "nope"), str(tmp_path / "dst"))
assert "Error: Source not found" in result
def test_copy_destination_exists_no_overwrite(self, tmp_path):
src = tmp_path / "src.txt"
src.write_text("data", encoding="utf-8")
dst = tmp_path / "dst.txt"
dst.write_text("existing", encoding="utf-8")
result = copy_path(str(src), str(dst))
assert "Error: Destination already exists" in result
def test_copy_destination_exists_overwrite(self, tmp_path):
src = tmp_path / "src.txt"
src.write_text("new", encoding="utf-8")
dst = tmp_path / "dst.txt"
dst.write_text("old", encoding="utf-8")
result = copy_path(str(src), str(dst), overwrite=True)
assert "Copied file" in result
assert dst.read_text(encoding="utf-8") == "new"
class TestMovePath:
def test_move_file(self, tmp_path):
src = tmp_path / "src.txt"
src.write_text("data", encoding="utf-8")
dst = tmp_path / "dst.txt"
result = move_path(str(src), str(dst))
assert "Moved" in result
assert not src.exists()
assert dst.read_text(encoding="utf-8") == "data"
def test_move_source_not_found(self, tmp_path):
result = move_path(str(tmp_path / "nope"), str(tmp_path / "dst"))
assert "Error: Source not found" in result
def test_move_destination_exists_no_overwrite(self, tmp_path):
src = tmp_path / "src.txt"
src.write_text("data", encoding="utf-8")
dst = tmp_path / "dst.txt"
dst.write_text("existing", encoding="utf-8")
result = move_path(str(src), str(dst))
assert "Error: Destination already exists" in result
class TestDeletePath:
def test_delete_file(self, tmp_path):
f = tmp_path / "del.txt"
f.write_text("bye", encoding="utf-8")
result = delete_path(str(f))
assert "Deleted file" in result
assert not f.exists()
def test_delete_empty_dir(self, tmp_path):
d = tmp_path / "emptydir"
d.mkdir()
result = delete_path(str(d))
assert "Deleted directory" in result
assert not d.exists()
def test_delete_nonempty_dir_without_recursive(self, tmp_path):
d = tmp_path / "fulldir"
d.mkdir()
(d / "file.txt").write_text("x", encoding="utf-8")
result = delete_path(str(d), recursive=False)
assert "Error: Directory is not empty" in result
assert d.exists()
def test_delete_nonempty_dir_recursive(self, tmp_path):
d = tmp_path / "fulldir"
d.mkdir()
(d / "file.txt").write_text("x", encoding="utf-8")
result = delete_path(str(d), recursive=True)
assert "Deleted directory" in result
assert not d.exists()
def test_delete_not_found(self, tmp_path):
result = delete_path(str(tmp_path / "ghost"))
assert "Error: Path not found" in result
class TestListDirectory:
def test_list_basic(self, tmp_path):
(tmp_path / "a.txt").write_text("a", encoding="utf-8")
(tmp_path / "b.txt").write_text("b", encoding="utf-8")
result = list_directory(str(tmp_path))
assert "a.txt" in result
assert "b.txt" in result
def test_list_with_pattern(self, tmp_path):
(tmp_path / "hello.py").write_text("x", encoding="utf-8")
(tmp_path / "hello.txt").write_text("x", encoding="utf-8")
result = list_directory(str(tmp_path), pattern="*.py")
assert "hello.py" in result
assert "hello.txt" not in result
def test_list_hides_hidden_by_default(self, tmp_path):
(tmp_path / ".hidden").write_text("x", encoding="utf-8")
(tmp_path / "visible").write_text("x", encoding="utf-8")
result = list_directory(str(tmp_path))
assert ".hidden" not in result
assert "visible" in result
def test_list_shows_hidden_when_enabled(self, tmp_path):
(tmp_path / ".hidden").write_text("x", encoding="utf-8")
result = list_directory(str(tmp_path), show_hidden=True)
assert ".hidden" in result
def test_list_empty(self, tmp_path):
result = list_directory(str(tmp_path))
assert "empty" in result.lower()
def test_list_not_found(self, tmp_path):
result = list_directory(str(tmp_path / "nope"))
assert "Error: Directory not found" in result
def test_dirs_listed_before_files(self, tmp_path):
(tmp_path / "z_file.txt").write_text("x", encoding="utf-8")
(tmp_path / "a_dir").mkdir()
result = list_directory(str(tmp_path))
dir_pos = result.index("a_dir")
file_pos = result.index("z_file.txt")
assert dir_pos < file_pos
class TestSearchFiles:
def test_search_basic(self, tmp_path):
(tmp_path / "a.py").write_text("x", encoding="utf-8")
(tmp_path / "b.txt").write_text("x", encoding="utf-8")
result = search_files(str(tmp_path), "*.py")
assert "a.py" in result
assert "b.txt" not in result
def test_search_recursive(self, tmp_path):
sub = tmp_path / "sub"
sub.mkdir()
(sub / "deep.py").write_text("x", encoding="utf-8")
result = search_files(str(tmp_path), "*.py", recursive=True)
assert "deep.py" in result
def test_search_no_matches(self, tmp_path):
result = search_files(str(tmp_path), "*.xyz")
assert "No matches found" in result
def test_search_path_not_found(self, tmp_path):
result = search_files(str(tmp_path / "nope"), "*.py")
assert "Error: Search path not found" in result
class TestGetFileInfo:
def test_file_info(self, tmp_path):
f = tmp_path / "info.txt"
f.write_text("hello", encoding="utf-8")
result = get_file_info(str(f))
assert "Type: File" in result
assert "Extension: .txt" in result
assert "5" in result # 5 bytes
def test_dir_info(self, tmp_path):
d = tmp_path / "mydir"
d.mkdir()
(d / "child.txt").write_text("x", encoding="utf-8")
result = get_file_info(str(d))
assert "Type: Directory" in result
assert "1 files" in result
def test_not_found(self, tmp_path):
result = get_file_info(str(tmp_path / "nope"))
assert "Error: Path not found" in result