from unittest.mock import MagicMock, patch import httpx import pytest from openai import RateLimitError import translate from translate import translate_feed, translate_html # ── Helpers ─────────────────────────────────────────────────────────────────── def _openai_response(text: str) -> MagicMock: m = MagicMock() m.choices = [MagicMock()] m.choices[0].message.content = text return m def _rate_limit_error() -> RateLimitError: req = httpx.Request("POST", "https://api.openai.com/v1/chat/completions") resp = httpx.Response(429, request=req) return RateLimitError("Rate limit exceeded", response=resp, body=None) # ── translate() ─────────────────────────────────────────────────────────────── def test_translate_empty_string_unchanged(db_conn): with patch("translate._client") as mock_client: result = translate.translate("", "sk", db_conn) assert result == "" mock_client.chat.completions.create.assert_not_called() def test_translate_whitespace_unchanged(db_conn): with patch("translate._client") as mock_client: result = translate.translate(" ", "sk", db_conn) assert result == " " mock_client.chat.completions.create.assert_not_called() def test_translate_calls_openai_on_cache_miss(db_conn): with patch("translate._client") as mock_client: mock_client.chat.completions.create.return_value = _openai_response("Ahoj") result = translate.translate("Hello", "sk", db_conn) assert result == "Ahoj" mock_client.chat.completions.create.assert_called_once() def test_translate_returns_cache_on_hit(db_conn): with patch("translate._client") as mock_client: mock_client.chat.completions.create.return_value = _openai_response("Ahoj") translate.translate("Hello", "sk", db_conn) result = translate.translate("Hello", "sk", db_conn) assert result == "Ahoj" assert mock_client.chat.completions.create.call_count == 1 def test_translate_on_error_returns_original(db_conn): with patch("translate._client") as mock_client: mock_client.chat.completions.create.side_effect = Exception("API down") result = translate.translate("Hello", "sk", db_conn) assert result == "Hello" def test_translate_error_not_cached(db_conn): with patch("translate._client") as mock_client: mock_client.chat.completions.create.side_effect = Exception("API down") translate.translate("Hello", "sk", db_conn) mock_client.chat.completions.create.side_effect = None mock_client.chat.completions.create.return_value = _openai_response("Ahoj") result = translate.translate("Hello", "sk", db_conn) assert result == "Ahoj" assert mock_client.chat.completions.create.call_count == 2 # ── _call_openai() retry / backoff ──────────────────────────────────────────── def test_call_openai_retries_on_rate_limit(db_conn): with patch("translate.time.sleep"), \ patch("translate._client") as mock_client: mock_client.chat.completions.create.side_effect = [ _rate_limit_error(), _rate_limit_error(), _openai_response("Preložený"), ] result = translate._call_openai("Hello", "sk") assert result == "Preložený" assert mock_client.chat.completions.create.call_count == 3 def test_call_openai_raises_after_max_retries(): with patch("translate.time.sleep"), \ patch("translate._client") as mock_client: mock_client.chat.completions.create.side_effect = _rate_limit_error() with pytest.raises(RateLimitError): translate._call_openai("Hello", "sk") assert mock_client.chat.completions.create.call_count == 5 def test_call_openai_backoff_increases(): with patch("translate.time.sleep") as mock_sleep, \ patch("translate._client") as mock_client: mock_client.chat.completions.create.side_effect = [ _rate_limit_error(), _rate_limit_error(), _rate_limit_error(), _openai_response("ok"), ] translate._call_openai("Hello", "sk") delays = [c.args[0] for c in mock_sleep.call_args_list] assert delays == [1.0, 2.0, 4.0] # ── translate_html() ────────────────────────────────────────────────────────── def test_translate_html_preserves_img_tags(db_conn): with patch("translate._client") as mock_client: mock_client.chat.completions.create.return_value = _openai_response("
Ahoj
") result = translate_html('Hello
', "sk", db_conn)
assert '
' in result
assert "Ahoj" in result
def test_translate_html_strips_img_before_api_call(db_conn):
with patch("translate._client") as mock_client:
mock_client.chat.completions.create.return_value = _openai_response("Ahoj
") translate_html('Hello
', "sk", db_conn)
sent = mock_client.chat.completions.create.call_args[1]["messages"][1]["content"]
assert "