First working, tray version
This commit is contained in:
324
tests/test_file_sync.py
Normal file
324
tests/test_file_sync.py
Normal file
@@ -0,0 +1,324 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user