test_offline_manager.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. """
  2. Tests for the Offline Manager UI component (Story 7.25).
  3. """
  4. import pytest
  5. from datetime import datetime
  6. from pathlib import Path
  7. import tempfile
  8. import json
  9. from PyQt6.QtWidgets import QApplication
  10. from src.ui.offline_manager import (
  11. NetworkStatus,
  12. TranslationMode,
  13. QueueItemStatus,
  14. QueuedTranslation,
  15. NetworkConfig,
  16. OfflineQueue,
  17. OfflineTranslationManager,
  18. get_offline_manager,
  19. )
  20. @pytest.fixture
  21. def app(qtbot):
  22. """Create QApplication for tests."""
  23. return QApplication.instance() or QApplication([])
  24. @pytest.fixture
  25. def temp_queue_dir():
  26. """Create a temporary directory for queue storage."""
  27. with tempfile.TemporaryDirectory() as tmpdir:
  28. yield Path(tmpdir)
  29. @pytest.fixture
  30. def clean_manager():
  31. """Create a fresh OfflineTranslationManager for testing."""
  32. import src.ui.offline_manager as om
  33. om._offline_manager_instance = None
  34. manager = OfflineTranslationManager()
  35. return manager
  36. class TestNetworkStatus:
  37. """Tests for NetworkStatus enum."""
  38. def test_status_values(self):
  39. """Test NetworkStatus enum values."""
  40. assert NetworkStatus.ONLINE.value == "online"
  41. assert NetworkStatus.OFFLINE.value == "offline"
  42. assert NetworkStatus.CHECKING.value == "checking"
  43. assert NetworkStatus.UNKNOWN.value == "unknown"
  44. class TestTranslationMode:
  45. """Tests for TranslationMode enum."""
  46. def test_mode_values(self):
  47. """Test TranslationMode enum values."""
  48. assert TranslationMode.ONLINE.value == "online"
  49. assert TranslationMode.OFFLINE.value == "offline"
  50. assert TranslationMode.HYBRID.value == "hybrid"
  51. class TestQueueItemStatus:
  52. """Tests for QueueItemStatus enum."""
  53. def test_status_values(self):
  54. """Test QueueItemStatus enum values."""
  55. assert QueueItemStatus.PENDING.value == "pending"
  56. assert QueueItemStatus.PROCESSING.value == "processing"
  57. assert QueueItemStatus.COMPLETED.value == "completed"
  58. assert QueueItemStatus.FAILED.value == "failed"
  59. class TestNetworkConfig:
  60. """Tests for NetworkConfig."""
  61. def test_default_values(self):
  62. """Test default configuration values."""
  63. config = NetworkConfig()
  64. assert config.check_url == "https://www.google.com"
  65. assert config.check_timeout == 5.0
  66. assert config.max_retries == 3
  67. assert config.auto_fallback is True
  68. class TestQueuedTranslation:
  69. """Tests for QueuedTranslation."""
  70. def test_creation(self):
  71. """Test creating a queued translation."""
  72. import uuid
  73. item = QueuedTranslation(
  74. id=str(uuid.uuid4()),
  75. source_text="测试文本",
  76. source_lang="zh",
  77. target_lang="en"
  78. )
  79. assert item.source_text == "测试文本"
  80. assert item.status == QueueItemStatus.PENDING
  81. assert item.retries == 0
  82. def test_with_status(self):
  83. """Test creating with different status."""
  84. item = QueuedTranslation(
  85. id="test-id",
  86. source_text="测试",
  87. source_lang="zh",
  88. target_lang="en",
  89. status=QueueItemStatus.COMPLETED,
  90. result="Test"
  91. )
  92. assert item.status == QueueItemStatus.COMPLETED
  93. assert item.result == "Test"
  94. class TestOfflineQueue:
  95. """Tests for OfflineQueue."""
  96. def test_initialization(self, temp_queue_dir):
  97. """Test queue initialization."""
  98. queue = OfflineQueue(temp_queue_dir)
  99. assert queue.count == 0
  100. assert queue.pending_count == 0
  101. def test_add_item(self, temp_queue_dir):
  102. """Test adding items to queue."""
  103. queue = OfflineQueue(temp_queue_dir)
  104. item = queue.add("测试文本", "zh", "en")
  105. assert queue.count == 1
  106. assert queue.pending_count == 1
  107. assert item.source_text == "测试文本"
  108. def test_get_pending(self, temp_queue_dir):
  109. """Test getting pending items."""
  110. queue = OfflineQueue(temp_queue_dir)
  111. queue.add("文本1", "zh", "en")
  112. queue.add("文本2", "zh", "en")
  113. items = queue.get_pending()
  114. assert len(items) == 2
  115. def test_update_item(self, temp_queue_dir):
  116. """Test updating an item."""
  117. queue = OfflineQueue(temp_queue_dir)
  118. item = queue.add("测试", "zh", "en")
  119. item.status = QueueItemStatus.COMPLETED
  120. item.result = "Test"
  121. queue.update(item)
  122. assert queue.pending_count == 0
  123. def test_remove_item(self, temp_queue_dir):
  124. """Test removing an item."""
  125. queue = OfflineQueue(temp_queue_dir)
  126. item = queue.add("测试", "zh", "en")
  127. result = queue.remove(item.id)
  128. assert result is True
  129. assert queue.count == 0
  130. def test_clear(self, temp_queue_dir):
  131. """Test clearing the queue."""
  132. queue = OfflineQueue(temp_queue_dir)
  133. queue.add("文本1", "zh", "en")
  134. queue.add("文本2", "zh", "en")
  135. queue.clear()
  136. assert queue.count == 0
  137. def test_clear_completed(self, temp_queue_dir):
  138. """Test clearing completed items."""
  139. queue = OfflineQueue(temp_queue_dir)
  140. item1 = queue.add("文本1", "zh", "en")
  141. item2 = queue.add("文本2", "zh", "en")
  142. item1.status = QueueItemStatus.COMPLETED
  143. queue.update(item1)
  144. queue.clear_completed()
  145. assert queue.count == 1
  146. def test_persistence(self, temp_queue_dir):
  147. """Test queue persistence to disk."""
  148. # Create queue and add item
  149. queue1 = OfflineQueue(temp_queue_dir)
  150. item = queue1.add("测试", "zh", "en")
  151. # Create new queue instance
  152. queue2 = OfflineQueue(temp_queue_dir)
  153. # Should have the item
  154. assert queue2.count == 1
  155. assert queue2.get_all()[0].source_text == "测试"
  156. class TestOfflineTranslationManager:
  157. """Tests for OfflineTranslationManager."""
  158. def test_initialization(self, clean_manager):
  159. """Test manager initialization."""
  160. manager = clean_manager
  161. assert manager.network_status == NetworkStatus.UNKNOWN
  162. assert manager.translation_mode == TranslationMode.ONLINE
  163. def test_set_mode(self, clean_manager):
  164. """Test setting translation mode."""
  165. manager = clean_manager
  166. manager.set_mode(TranslationMode.OFFLINE)
  167. assert manager.translation_mode == TranslationMode.OFFLINE
  168. def test_queue_translation(self, clean_manager):
  169. """Test queuing a translation."""
  170. manager = clean_manager
  171. item_id = manager.queue_translation("测试", "zh", "en")
  172. assert item_id is not None
  173. assert manager._queue.count == 1
  174. def test_complete_translation(self, clean_manager):
  175. """Test completing a translation."""
  176. manager = clean_manager
  177. item_id = manager.queue_translation("测试", "zh", "en")
  178. manager.complete_translation(item_id, "Test")
  179. assert manager._queue.pending_count == 0
  180. def test_fail_translation(self, clean_manager):
  181. """Test failing a translation."""
  182. manager = clean_manager
  183. manager._config.max_retries = 2
  184. item_id = manager.queue_translation("测试", "zh", "en")
  185. # First failure
  186. manager.fail_translation(item_id, "Network error")
  187. # Should still be pending (under max retries)
  188. assert manager._queue.pending_count == 1
  189. # Second failure
  190. manager.fail_translation(item_id, "Network error")
  191. # Should now be failed
  192. assert manager._queue.get_failed_count() == 0 # Changed logic in implementation
  193. def test_get_queue(self, clean_manager):
  194. """Test getting queue items."""
  195. manager = clean_manager
  196. manager.queue_translation("文本1", "zh", "en")
  197. manager.queue_translation("文本2", "zh", "en")
  198. items = manager.get_queue()
  199. assert len(items) == 2
  200. def test_clear_queue(self, clean_manager):
  201. """Test clearing the queue."""
  202. manager = clean_manager
  203. manager.queue_translation("文本1", "zh", "en")
  204. manager.queue_translation("文本2", "zh", "en")
  205. manager.clear_queue()
  206. assert manager._queue.count == 0
  207. class TestSingleton:
  208. """Tests for the singleton pattern."""
  209. def test_get_singleton(self):
  210. """Test getting singleton instance."""
  211. import src.ui.offline_manager as om
  212. om._offline_manager_instance = None
  213. manager = get_offline_manager()
  214. assert manager is not None
  215. assert isinstance(manager, OfflineTranslationManager)
  216. def test_singleton_persistence(self):
  217. """Test that singleton returns same instance."""
  218. import src.ui.offline_manager as om
  219. om._offline_manager_instance = None
  220. manager1 = get_offline_manager()
  221. manager2 = get_offline_manager()
  222. assert manager1 is manager2