- Updated the language configuration to use a single source of truth from `DEFAULT_LANGUAGE` for the bot, API, and Mini App, eliminating auto-detection from user settings. - Refactored the `get_lang` function to always return `DEFAULT_LANGUAGE`, ensuring consistent language usage throughout the application. - Modified the handling of language in various components, including API responses and UI elements, to reflect the new language management approach. - Enhanced documentation and comments to clarify the changes in language handling. - Added unit tests to verify the new language handling behavior and ensure coverage for the updated functionality.
105 lines
4.5 KiB
Python
105 lines
4.5 KiB
Python
"""Tests for duty_teller.api.dependencies (lang, auth error, date validation, private client)."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
import duty_teller.api.dependencies as deps
|
|
import duty_teller.config as config
|
|
|
|
|
|
class TestLangFromAcceptLanguage:
|
|
"""Tests for _lang_from_accept_language: always returns config.DEFAULT_LANGUAGE."""
|
|
|
|
def test_always_returns_default_language(self):
|
|
"""Header is ignored; result is always config.DEFAULT_LANGUAGE."""
|
|
assert deps._lang_from_accept_language(None) == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language("") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language(" ") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language("ru-RU,ru;q=0.9") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language("en-US") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language("zz") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language("x") == config.DEFAULT_LANGUAGE
|
|
|
|
def test_returns_ru_when_default_language_is_ru(self):
|
|
with patch.object(config, "DEFAULT_LANGUAGE", "ru"):
|
|
assert deps._lang_from_accept_language("en-US") == "ru"
|
|
assert deps._lang_from_accept_language(None) == "ru"
|
|
|
|
def test_returns_en_when_default_language_is_en(self):
|
|
with patch.object(config, "DEFAULT_LANGUAGE", "en"):
|
|
assert deps._lang_from_accept_language("ru-RU") == "en"
|
|
assert deps._lang_from_accept_language(None) == "en"
|
|
|
|
|
|
class TestAuthErrorDetail:
|
|
"""Tests for _auth_error_detail."""
|
|
|
|
def test_hash_mismatch_uses_bad_signature_key(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Bad signature"
|
|
result = deps._auth_error_detail("hash_mismatch", "en")
|
|
assert result == "Bad signature"
|
|
mock_t.assert_called_once_with("en", "api.auth_bad_signature")
|
|
|
|
def test_other_reason_uses_auth_invalid_key(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Invalid auth"
|
|
result = deps._auth_error_detail("expired", "ru")
|
|
assert result == "Invalid auth"
|
|
mock_t.assert_called_once_with("ru", "api.auth_invalid")
|
|
|
|
|
|
class TestValidateDutyDates:
|
|
"""Tests for _validate_duty_dates."""
|
|
|
|
def test_valid_range_no_exception(self):
|
|
deps._validate_duty_dates("2025-01-01", "2025-01-31", "en")
|
|
|
|
def test_bad_format_raises_400_with_i18n(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Bad format message"
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
deps._validate_duty_dates("01-01-2025", "2025-01-31", "en")
|
|
assert exc_info.value.status_code == 400
|
|
assert exc_info.value.detail == "Bad format message"
|
|
mock_t.assert_called_with("en", "dates.bad_format")
|
|
|
|
def test_from_after_to_raises_400_with_i18n(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "From after to message"
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
deps._validate_duty_dates("2025-02-01", "2025-01-01", "ru")
|
|
assert exc_info.value.status_code == 400
|
|
assert exc_info.value.detail == "From after to message"
|
|
mock_t.assert_called_with("ru", "dates.from_after_to")
|
|
|
|
|
|
class TestFetchDutiesResponse:
|
|
"""Tests for fetch_duties_response (DutyWithUser list with phone, username)."""
|
|
|
|
def test_fetch_duties_response_includes_phone_and_username(self):
|
|
"""get_duties returns (Duty, full_name, phone, username); response has phone, username."""
|
|
from types import SimpleNamespace
|
|
|
|
from duty_teller.db.schemas import DutyWithUser
|
|
|
|
duty = SimpleNamespace(
|
|
id=1,
|
|
user_id=10,
|
|
start_at="2025-01-15T09:00:00Z",
|
|
end_at="2025-01-15T18:00:00Z",
|
|
event_type="duty",
|
|
)
|
|
rows = [(duty, "Alice", "+79001234567", "alice_dev")]
|
|
with patch.object(deps, "get_duties", return_value=rows):
|
|
result = deps.fetch_duties_response(
|
|
type("Session", (), {})(), "2025-01-01", "2025-01-31"
|
|
)
|
|
assert len(result) == 1
|
|
assert isinstance(result[0], DutyWithUser)
|
|
assert result[0].full_name == "Alice"
|
|
assert result[0].phone == "+79001234567"
|
|
assert result[0].username == "alice_dev"
|