Files
duty-teller/tests/test_api_dependencies.py
Nikolay Tatarinov 67ba9826c7 feat: unify language handling across the application
- 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.
2026-03-02 23:05:28 +03:00

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"