""" Tests for UI models - no GUI required. """ import pytest from pathlib import Path from datetime import datetime, timedelta from src.ui.models import ( FileItem, FileStatus, TranslationTask, TaskStatus, ProgressUpdate, Statistics, ) class TestFileItem: """Test FileItem data model.""" def test_file_item_creation_defaults(self): """Test creating a file item with default values.""" item = FileItem( path=Path("/test/file.txt"), name="file.txt", size=2048, ) assert item.name == "file.txt" assert item.path == Path("/test/file.txt") assert item.size == 2048 assert item.status == FileStatus.PENDING assert item.chapters == 0 assert item.total_words == 0 assert item.translated_words == 0 assert item.error_message is None assert isinstance(item.added_time, datetime) def test_file_item_creation_with_values(self): """Test creating a file item with specific values.""" now = datetime.now() item = FileItem( path=Path("/test/novel.txt"), name="novel.txt", size=1024 * 100, status=FileStatus.TRANSLATING, chapters=50, total_words=100000, translated_words=25000, error_message=None, added_time=now, ) assert item.name == "novel.txt" assert item.status == FileStatus.TRANSLATING assert item.chapters == 50 assert item.total_words == 100000 assert item.translated_words == 25000 def test_progress_calculation(self): """Test progress percentage calculation.""" item = FileItem( path=Path("/test/file.txt"), name="file.txt", size=1024, total_words=1000, translated_words=500, ) assert item.progress == 50.0 def test_progress_zero_when_no_total(self): """Test progress is zero when total_words is 0.""" item = FileItem( path=Path("/test/file.txt"), name="file.txt", size=1024, total_words=0, translated_words=0, ) assert item.progress == 0.0 def test_progress_complete(self): """Test progress when translation is complete.""" item = FileItem( path=Path("/test/file.txt"), name="file.txt", size=1024, total_words=1000, translated_words=1000, ) assert item.progress == 100.0 def test_size_formatting_bytes(self): """Test size formatting for bytes.""" item = FileItem( path=Path("/test/small.txt"), name="small.txt", size=512, ) assert "512" in item.size_formatted assert "B" in item.size_formatted def test_size_formatting_kilobytes(self): """Test size formatting for kilobytes.""" item = FileItem( path=Path("/test/medium.txt"), name="medium.txt", size=2048, ) assert "KB" in item.size_formatted def test_size_formatting_megabytes(self): """Test size formatting for megabytes.""" item = FileItem( path=Path("/test/large.txt"), name="large.txt", size=1024 * 1024 * 5, ) assert "MB" in item.size_formatted class TestTranslationTask: """Test TranslationTask data model.""" def test_task_creation_defaults(self): """Test creating a task with default values.""" task = TranslationTask(id="task-123") assert task.id == "task-123" assert task.status == TaskStatus.IDLE assert task.current_stage == "" assert task.current_chapter == 0 assert task.total_chapters == 0 assert task.start_time is None assert task.end_time is None assert task.error_message is None assert task.file_items == [] def test_task_creation_with_file_items(self): """Test creating a task with file items.""" file1 = FileItem(Path("/test/file1.txt"), "file1.txt", 1024) file2 = FileItem(Path("/test/file2.txt"), "file2.txt", 2048) task = TranslationTask( id="task-456", file_items=[file1, file2], status=TaskStatus.RUNNING, current_stage="translating", current_chapter=5, total_chapters=10, ) assert len(task.file_items) == 2 assert task.status == TaskStatus.RUNNING assert task.current_stage == "translating" assert task.current_chapter == 5 assert task.total_chapters == 10 def test_progress_calculation(self): """Test task progress calculation.""" task = TranslationTask( id="task-1", current_chapter=25, total_chapters=100, ) assert task.progress == 25.0 def test_progress_zero_when_no_total(self): """Test progress is zero when total_chapters is 0.""" task = TranslationTask( id="task-1", current_chapter=0, total_chapters=0, ) assert task.progress == 0.0 def test_elapsed_time_without_start(self): """Test elapsed time when task hasn't started.""" task = TranslationTask(id="task-1") assert task.elapsed_time is None def test_elapsed_time_with_start(self): """Test elapsed time calculation.""" start = datetime.now() - timedelta(seconds=60) task = TranslationTask( id="task-1", start_time=start, ) # Should be approximately 60 seconds assert task.elapsed_time is not None assert 59 <= task.elapsed_time <= 61 def test_elapsed_time_with_end(self): """Test elapsed time when task is complete.""" start = datetime.now() - timedelta(seconds=120) end = start + timedelta(seconds=60) task = TranslationTask( id="task-1", start_time=start, end_time=end, ) assert task.elapsed_time == 60.0 def test_is_running(self): """Test is_running property.""" task_running = TranslationTask(id="task-1", status=TaskStatus.RUNNING) task_idle = TranslationTask(id="task-2", status=TaskStatus.IDLE) assert task_running.is_running is True assert task_idle.is_running is False def test_is_paused(self): """Test is_paused property.""" task_paused = TranslationTask(id="task-1", status=TaskStatus.PAUSED) task_running = TranslationTask(id="task-2", status=TaskStatus.RUNNING) assert task_paused.is_paused is True assert task_running.is_paused is False def test_can_start(self): """Test can_start property.""" statuses_can_start = [ TaskStatus.IDLE, TaskStatus.PAUSED, TaskStatus.FAILED, ] for status in statuses_can_start: task = TranslationTask(id=f"task-{status.value}", status=status) assert task.can_start is True, f"Status {status} should be startable" # These cannot be started task_running = TranslationTask(id="task-running", status=TaskStatus.RUNNING) task_completed = TranslationTask(id="task-completed", status=TaskStatus.COMPLETED) task_cancelled = TranslationTask(id="task-cancelled", status=TaskStatus.CANCELLED) assert task_running.can_start is False assert task_completed.can_start is False assert task_cancelled.can_start is False def test_can_pause(self): """Test can_pause property.""" task_running = TranslationTask(id="task-1", status=TaskStatus.RUNNING) task_idle = TranslationTask(id="task-2", status=TaskStatus.IDLE) assert task_running.can_pause is True assert task_idle.can_pause is False def test_can_cancel(self): """Test can_cancel property.""" task_running = TranslationTask(id="task-1", status=TaskStatus.RUNNING) task_paused = TranslationTask(id="task-2", status=TaskStatus.PAUSED) task_idle = TranslationTask(id="task-3", status=TaskStatus.IDLE) assert task_running.can_cancel is True assert task_paused.can_cancel is True assert task_idle.can_cancel is False class TestProgressUpdate: """Test ProgressUpdate data model.""" def test_progress_update_creation(self): """Test creating a progress update.""" update = ProgressUpdate( task_id="task-123", stage="translating", current=5, total=10, message="Processing chapter 5", elapsed_seconds=60, eta_seconds=120, ) assert update.task_id == "task-123" assert update.stage == "translating" assert update.current == 5 assert update.total == 10 assert update.message == "Processing chapter 5" assert update.elapsed_seconds == 60 assert update.eta_seconds == 120 def test_progress_calculation(self): """Test progress percentage calculation.""" update = ProgressUpdate( task_id="task-1", stage="translating", current=3, total=10, ) assert update.progress == 30.0 def test_progress_zero_when_no_total(self): """Test progress is zero when total is 0.""" update = ProgressUpdate( task_id="task-1", stage="translating", current=0, total=0, ) assert update.progress == 0.0 def test_progress_complete(self): """Test progress when complete.""" update = ProgressUpdate( task_id="task-1", stage="translating", current=10, total=10, ) assert update.progress == 100.0 class TestStatistics: """Test Statistics data model.""" def test_statistics_defaults(self): """Test statistics with default values.""" stats = Statistics() assert stats.total_translated_words == 0 assert stats.total_chapters == 0 assert stats.total_time_seconds == 0 assert stats.successful_tasks == 0 assert stats.failed_tasks == 0 assert stats.terminology_usage_rate == 0.0 def test_statistics_with_values(self): """Test statistics with specific values.""" stats = Statistics( total_translated_words=50000, total_chapters=100, total_time_seconds=3000, successful_tasks=5, failed_tasks=1, terminology_usage_rate=85.5, ) assert stats.total_translated_words == 50000 assert stats.total_chapters == 100 assert stats.total_time_seconds == 3000 assert stats.successful_tasks == 5 assert stats.failed_tasks == 1 assert stats.terminology_usage_rate == 85.5 def test_average_speed_calculation(self): """Test average translation speed calculation.""" stats = Statistics( total_translated_words=6000, # 6000 words total_time_seconds=120, # 2 minutes ) # 6000 words / 120 seconds * 60 = 3000 words/minute assert stats.average_speed == 3000.0 def test_average_speed_zero_time(self): """Test average speed when time is zero.""" stats = Statistics( total_translated_words=1000, total_time_seconds=0, ) assert stats.average_speed == 0.0 def test_completion_rate_calculation(self): """Test task completion rate calculation.""" stats = Statistics( successful_tasks=9, failed_tasks=1, ) # 9 / (9 + 1) * 100 = 90% assert stats.completion_rate == 90.0 def test_completion_rate_no_tasks(self): """Test completion rate when no tasks.""" stats = Statistics() assert stats.completion_rate == 0.0 def test_total_tasks(self): """Test total tasks property.""" stats = Statistics( successful_tasks=5, failed_tasks=2, ) assert stats.total_tasks == 7 class TestFileStatus: """Test FileStatus enum.""" def test_all_status_values(self): """Test all status values exist.""" assert FileStatus.PENDING.value == "pending" assert FileStatus.IMPORTING.value == "importing" assert FileStatus.READY.value == "ready" assert FileStatus.TRANSLATING.value == "translating" assert FileStatus.PAUSED.value == "paused" assert FileStatus.COMPLETED.value == "completed" assert FileStatus.FAILED.value == "failed" class TestTaskStatus: """Test TaskStatus enum.""" def test_all_status_values(self): """Test all status values exist.""" assert TaskStatus.IDLE.value == "idle" assert TaskStatus.RUNNING.value == "running" assert TaskStatus.PAUSED.value == "paused" assert TaskStatus.COMPLETED.value == "completed" assert TaskStatus.FAILED.value == "failed" assert TaskStatus.CANCELLED.value == "cancelled"