"""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)