2
0

test_one_click_translation.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. """
  2. Tests for the One-Click Translation Workflow component (Story 7.20).
  3. """
  4. import pytest
  5. from pathlib import Path
  6. import tempfile
  7. from datetime import datetime
  8. from PyQt6.QtWidgets import QApplication
  9. from src.ui.one_click_translation import (
  10. WorkflowStep,
  11. WorkflowConfig,
  12. WorkflowResult,
  13. WorkflowProgress,
  14. OneClickWorkflowWidget,
  15. OneClickTranslationDialog,
  16. )
  17. @pytest.fixture
  18. def app(qtbot):
  19. """Create QApplication for tests."""
  20. return QApplication.instance() or QApplication([])
  21. @pytest.fixture
  22. def sample_config():
  23. """Create sample workflow config."""
  24. return WorkflowConfig(
  25. source_lang="zh",
  26. target_lang="en",
  27. extract_terms=True,
  28. use_gpu=True
  29. )
  30. @pytest.fixture
  31. def sample_result():
  32. """Create sample workflow result."""
  33. return WorkflowResult(
  34. success=True,
  35. steps_completed=[
  36. WorkflowStep.IMPORTING,
  37. WorkflowStep.CLEANING,
  38. WorkflowStep.EXTRACTING_TERMS,
  39. WorkflowStep.TRANSLATING,
  40. WorkflowStep.FORMATTING,
  41. WorkflowStep.EXPORTING,
  42. ],
  43. total_chapters=10,
  44. completed_chapters=10,
  45. failed_chapters=0,
  46. total_words=30000,
  47. translated_words=29400,
  48. elapsed_time_seconds=600.0,
  49. output_path=Path("/output/translation")
  50. )
  51. class TestWorkflowStep:
  52. """Tests for WorkflowStep enum."""
  53. def test_step_values(self):
  54. """Test WorkflowStep enum values."""
  55. assert WorkflowStep.IDLE.value == "idle"
  56. assert WorkflowStep.IMPORTING.value == "importing"
  57. assert WorkflowStep.TRANSLATING.value == "translating"
  58. assert WorkflowStep.COMPLETED.value == "completed"
  59. assert WorkflowStep.FAILED.value == "failed"
  60. class TestWorkflowConfig:
  61. """Tests for WorkflowConfig."""
  62. def test_default_values(self):
  63. """Test default configuration values."""
  64. config = WorkflowConfig()
  65. assert config.clean_empty_lines is True
  66. assert config.max_segment_length == 900
  67. assert config.extract_terms is True
  68. assert config.use_gpu is True
  69. assert config.source_lang == "zh"
  70. assert config.target_lang == "en"
  71. def test_custom_values(self):
  72. """Test custom configuration."""
  73. config = WorkflowConfig(
  74. source_lang="ja",
  75. target_lang="ko",
  76. extract_terms=False,
  77. batch_size=16
  78. )
  79. assert config.source_lang == "ja"
  80. assert config.target_lang == "ko"
  81. assert config.extract_terms is False
  82. assert config.batch_size == 16
  83. class TestWorkflowResult:
  84. """Tests for WorkflowResult."""
  85. def test_success_result(self, sample_result):
  86. """Test successful result."""
  87. assert sample_result.success is True
  88. assert sample_result.completed_chapters == 10
  89. assert sample_result.translated_words == 29400
  90. def test_failure_result(self):
  91. """Test failed result."""
  92. result = WorkflowResult(
  93. success=False,
  94. steps_completed=[WorkflowStep.IMPORTING],
  95. error="Network error"
  96. )
  97. assert result.success is False
  98. assert result.error == "Network error"
  99. assert result.completed_chapters == 0
  100. def test_completion_percentage(self, sample_result):
  101. """Test chapter completion rate."""
  102. rate = sample_result.completed_chapters / sample_result.total_chapters
  103. assert rate == 1.0
  104. class TestWorkflowProgress:
  105. """Tests for WorkflowProgress."""
  106. def test_creation(self):
  107. """Test creating progress update."""
  108. progress = WorkflowProgress(
  109. current_step=WorkflowStep.TRANSLATING,
  110. step_name="翻译中",
  111. progress=50,
  112. overall_progress=60,
  113. message="正在处理..."
  114. )
  115. assert progress.current_step == WorkflowStep.TRANSLATING
  116. assert progress.progress == 50
  117. assert progress.overall_progress == 60
  118. def test_with_chapter(self):
  119. """Test progress with chapter info."""
  120. progress = WorkflowProgress(
  121. current_step=WorkflowStep.TRANSLATING,
  122. step_name="翻译中",
  123. progress=25,
  124. overall_progress=50,
  125. message="翻译中",
  126. chapter="Chapter 1"
  127. )
  128. assert progress.chapter == "Chapter 1"
  129. class TestOneClickWorkflowWidget:
  130. """Tests for OneClickWorkflowWidget."""
  131. def test_initialization(self, qtbot):
  132. """Test widget initialization."""
  133. widget = OneClickWorkflowWidget()
  134. qtbot.addWidget(widget)
  135. assert widget._input_files == []
  136. assert widget._config is not None
  137. def test_config_property(self, qtbot):
  138. """Test config property."""
  139. widget = OneClickWorkflowWidget()
  140. qtbot.addWidget(widget)
  141. config = widget.config
  142. assert config is not None
  143. assert isinstance(config, WorkflowConfig)
  144. def test_set_input_files(self, qtbot, tmp_path):
  145. """Test setting input files."""
  146. widget = OneClickWorkflowWidget()
  147. qtbot.addWidget(widget)
  148. files = [tmp_path / "test1.txt", tmp_path / "test2.md"]
  149. for f in files:
  150. f.write_text("content")
  151. widget.set_input_files(files)
  152. assert widget.file_count == 2
  153. def test_update_files_display(self, qtbot, tmp_path):
  154. """Test file display update."""
  155. widget = OneClickWorkflowWidget()
  156. qtbot.addWidget(widget)
  157. # No files
  158. widget._update_files_display()
  159. assert widget._start_btn.isEnabled() is False
  160. # Add files
  161. files = [tmp_path / "test.txt"]
  162. files[0].write_text("content")
  163. widget._input_files = files
  164. widget._update_files_display()
  165. assert widget._start_btn.isEnabled() is True
  166. assert "1 个项目" in widget._files_label.text()
  167. def test_show_result(self, qtbot, sample_result):
  168. """Test showing result."""
  169. widget = OneClickWorkflowWidget()
  170. qtbot.addWidget(widget)
  171. widget._show_result(sample_result)
  172. assert widget._result_group.isVisible() is True
  173. assert widget._last_result == sample_result
  174. def test_reset_ui(self, qtbot):
  175. """Test UI reset."""
  176. widget = OneClickWorkflowWidget()
  177. qtbot.addWidget(widget)
  178. # Simulate some progress
  179. widget._progress_bar.setValue(50)
  180. widget._result_group.setVisible(True)
  181. widget._reset_ui()
  182. assert widget._progress_bar.value() == 0
  183. assert widget._result_group.isVisible() is False
  184. assert widget._cancel_btn.isEnabled() is False
  185. class TestOneClickTranslationDialog:
  186. """Tests for OneClickTranslationDialog."""
  187. def test_initialization_without_files(self, qtbot):
  188. """Test dialog initialization without files."""
  189. dialog = OneClickTranslationDialog()
  190. qtbot.addWidget(dialog)
  191. assert dialog is not None
  192. assert dialog._widget is not None
  193. def test_initialization_with_files(self, qtbot, tmp_path):
  194. """Test dialog initialization with files."""
  195. files = [tmp_path / "test.txt"]
  196. files[0].write_text("content")
  197. dialog = OneClickTranslationDialog(files)
  198. qtbot.addWidget(dialog)
  199. assert dialog is not None
  200. def test_set_input_files(self, qtbot, tmp_path):
  201. """Test setting input files on dialog."""
  202. dialog = OneClickTranslationDialog()
  203. qtbot.addWidget(dialog)
  204. files = [tmp_path / "test.txt"]
  205. files[0].write_text("content")
  206. dialog.set_input_files(files)
  207. assert dialog._widget.file_count == 1