Files
Vault/tests/test_file_sync.py

325 lines
9.1 KiB
Python
Raw Permalink Normal View History

2026-01-30 07:07:11 +01:00
"""Tests for file_sync module."""
import time
from pathlib import Path
import pytest
from src.core.file_sync import (
CopyProgress,
copy_directory_with_progress,
copy_file_with_progress,
delete_directory,
delete_file,
move_file,
sync_file,
)
class TestCopyProgress:
"""Tests for CopyProgress dataclass."""
def test_percent_calculation(self) -> None:
progress = CopyProgress(
src_path=Path("src"),
dst_path=Path("dst"),
bytes_copied=50,
total_bytes=100,
)
assert progress.percent == 50.0
def test_percent_with_zero_total(self) -> None:
progress = CopyProgress(
src_path=Path("src"),
dst_path=Path("dst"),
bytes_copied=0,
total_bytes=0,
)
assert progress.percent == 100.0
def test_is_complete_true(self) -> None:
progress = CopyProgress(
src_path=Path("src"),
dst_path=Path("dst"),
bytes_copied=100,
total_bytes=100,
)
assert progress.is_complete is True
def test_is_complete_false(self) -> None:
progress = CopyProgress(
src_path=Path("src"),
dst_path=Path("dst"),
bytes_copied=50,
total_bytes=100,
)
assert progress.is_complete is False
class TestCopyFileWithProgress:
"""Tests for copy_file_with_progress function."""
def test_copy_file(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
src.write_text("Hello, World!")
copy_file_with_progress(src, dst)
assert dst.exists()
assert dst.read_text() == "Hello, World!"
def test_copy_file_creates_parent_dirs(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "nested" / "deep" / "dest.txt"
src.write_text("content")
copy_file_with_progress(src, dst)
assert dst.exists()
assert dst.read_text() == "content"
def test_copy_file_with_callback(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
# Create a file larger than chunk size
content = "x" * 5000
src.write_text(content)
progress_calls: list[CopyProgress] = []
def callback(progress: CopyProgress) -> None:
progress_calls.append(progress)
copy_file_with_progress(src, dst, callback=callback, chunk_size=1000)
assert len(progress_calls) >= 1
assert progress_calls[-1].is_complete
def test_copy_file_preserves_timestamps(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
src.write_text("content")
# Get original timestamps
src_stat = src.stat()
copy_file_with_progress(src, dst)
dst_stat = dst.stat()
assert abs(src_stat.st_mtime - dst_stat.st_mtime) < 1
def test_copy_file_source_not_found(self, tmp_path: Path) -> None:
src = tmp_path / "nonexistent.txt"
dst = tmp_path / "dest.txt"
with pytest.raises(FileNotFoundError):
copy_file_with_progress(src, dst)
def test_copy_file_source_is_directory(self, tmp_path: Path) -> None:
src = tmp_path / "srcdir"
dst = tmp_path / "dest.txt"
src.mkdir()
with pytest.raises(IsADirectoryError):
copy_file_with_progress(src, dst)
def test_copy_file_destination_is_directory(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dstdir"
src.write_text("content")
dst.mkdir()
with pytest.raises(IsADirectoryError):
copy_file_with_progress(src, dst)
class TestCopyDirectoryWithProgress:
"""Tests for copy_directory_with_progress function."""
def test_copy_directory(self, tmp_path: Path) -> None:
src = tmp_path / "srcdir"
dst = tmp_path / "dstdir"
src.mkdir()
(src / "file1.txt").write_text("content1")
(src / "file2.txt").write_text("content2")
copy_directory_with_progress(src, dst)
assert dst.exists()
assert (dst / "file1.txt").read_text() == "content1"
assert (dst / "file2.txt").read_text() == "content2"
def test_copy_nested_directory(self, tmp_path: Path) -> None:
src = tmp_path / "srcdir"
dst = tmp_path / "dstdir"
src.mkdir()
(src / "nested").mkdir()
(src / "nested" / "deep.txt").write_text("deep content")
copy_directory_with_progress(src, dst)
assert (dst / "nested" / "deep.txt").read_text() == "deep content"
def test_copy_directory_not_found(self, tmp_path: Path) -> None:
src = tmp_path / "nonexistent"
dst = tmp_path / "dstdir"
with pytest.raises(FileNotFoundError):
copy_directory_with_progress(src, dst)
def test_copy_directory_source_is_file(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dstdir"
src.write_text("content")
with pytest.raises(NotADirectoryError):
copy_directory_with_progress(src, dst)
class TestDeleteFile:
"""Tests for delete_file function."""
def test_delete_file(self, tmp_path: Path) -> None:
file = tmp_path / "test.txt"
file.write_text("content")
delete_file(file)
assert not file.exists()
def test_delete_file_not_found(self, tmp_path: Path) -> None:
file = tmp_path / "nonexistent.txt"
with pytest.raises(FileNotFoundError):
delete_file(file)
def test_delete_file_is_directory(self, tmp_path: Path) -> None:
dir_path = tmp_path / "testdir"
dir_path.mkdir()
with pytest.raises(IsADirectoryError):
delete_file(dir_path)
class TestDeleteDirectory:
"""Tests for delete_directory function."""
def test_delete_directory(self, tmp_path: Path) -> None:
dir_path = tmp_path / "testdir"
dir_path.mkdir()
(dir_path / "file.txt").write_text("content")
delete_directory(dir_path)
assert not dir_path.exists()
def test_delete_nested_directory(self, tmp_path: Path) -> None:
dir_path = tmp_path / "testdir"
dir_path.mkdir()
(dir_path / "nested").mkdir()
(dir_path / "nested" / "deep.txt").write_text("content")
delete_directory(dir_path)
assert not dir_path.exists()
def test_delete_directory_not_found(self, tmp_path: Path) -> None:
dir_path = tmp_path / "nonexistent"
with pytest.raises(FileNotFoundError):
delete_directory(dir_path)
def test_delete_directory_is_file(self, tmp_path: Path) -> None:
file = tmp_path / "test.txt"
file.write_text("content")
with pytest.raises(NotADirectoryError):
delete_directory(file)
class TestMoveFile:
"""Tests for move_file function."""
def test_move_file(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
src.write_text("content")
move_file(src, dst)
assert not src.exists()
assert dst.exists()
assert dst.read_text() == "content"
def test_move_file_creates_parent_dirs(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "nested" / "deep" / "dest.txt"
src.write_text("content")
move_file(src, dst)
assert not src.exists()
assert dst.exists()
def test_move_file_not_found(self, tmp_path: Path) -> None:
src = tmp_path / "nonexistent.txt"
dst = tmp_path / "dest.txt"
with pytest.raises(FileNotFoundError):
move_file(src, dst)
class TestSyncFile:
"""Tests for sync_file function."""
def test_sync_new_file(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
src.write_text("content")
result = sync_file(src, dst)
assert result is True
assert dst.exists()
assert dst.read_text() == "content"
def test_sync_newer_source(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
# Create destination first
dst.write_text("old content")
time.sleep(0.1)
# Create newer source
src.write_text("new content")
result = sync_file(src, dst)
assert result is True
assert dst.read_text() == "new content"
def test_sync_older_source(self, tmp_path: Path) -> None:
src = tmp_path / "source.txt"
dst = tmp_path / "dest.txt"
# Create source first
src.write_text("old content")
time.sleep(0.1)
# Create newer destination
dst.write_text("new content")
result = sync_file(src, dst)
assert result is False
assert dst.read_text() == "new content"
def test_sync_file_not_found(self, tmp_path: Path) -> None:
src = tmp_path / "nonexistent.txt"
dst = tmp_path / "dest.txt"
with pytest.raises(FileNotFoundError):
sync_file(src, dst)