greetd-moongreet/tests/test_i18n.py
nevaforget 4cd73a430b fix: Audit-Findings — Realize-Handler, Thread-Safety, Input-Validierung
- _on_realize implementiert (war nur connected, nicht definiert)
- do_unrealize für as_file() Context-Manager-Cleanup
- threading.Lock für _greetd_sock Race Condition
- TOML-Parsing-Fehler abfangen statt Crash
- last-user Datei: Längen- und Zeichenvalidierung
- detect_locale: non-alpha LANG-Werte abweisen
- exec_cmd Plausibility-Check mit shutil.which
- Exception-Details ins Log statt in die UI
- subprocess.run Timeout für Power-Actions
- Sequence[Path] statt tuple[Path, ...] in get_sessions
- Mock-Server _recvall für fragmentierte Reads
- [behavior]-Config-Sektion entfernt (unimplementiert)
- Design Decisions in CLAUDE.md dokumentiert
2026-03-26 12:56:52 +01:00

127 lines
3.9 KiB
Python

# ABOUTME: Tests for locale detection and string lookup.
# ABOUTME: Verifies DE/EN selection based on system locale.
from pathlib import Path
import pytest
from moongreet.i18n import detect_locale, load_strings, Strings
class TestDetectLocale:
"""Tests for system locale detection."""
def test_reads_lang_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "de_DE.UTF-8")
result = detect_locale()
assert result == "de"
def test_reads_lang_without_region(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "en_US.UTF-8")
result = detect_locale()
assert result == "en"
def test_falls_back_to_locale_conf(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("LANG", raising=False)
locale_conf = tmp_path / "locale.conf"
locale_conf.write_text("LANG=de_AT.UTF-8\n")
result = detect_locale(locale_conf_path=locale_conf)
assert result == "de"
def test_defaults_to_english(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("LANG", raising=False)
missing = tmp_path / "nonexistent"
result = detect_locale(locale_conf_path=missing)
assert result == "en"
def test_handles_bare_language_code(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "de")
result = detect_locale()
assert result == "de"
def test_handles_c_locale(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "C")
result = detect_locale()
assert result == "en"
def test_handles_posix_locale(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "POSIX")
result = detect_locale()
assert result == "en"
def test_rejects_non_alpha_lang(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("LANG", "../../etc")
result = detect_locale()
assert result == "en"
class TestLoadStrings:
"""Tests for loading the correct string table."""
def test_loads_german_strings(self) -> None:
strings = load_strings("de")
assert strings.password_placeholder == "Passwort"
assert strings.reboot_tooltip == "Neustart"
assert strings.shutdown_tooltip == "Herunterfahren"
def test_loads_english_strings(self) -> None:
strings = load_strings("en")
assert strings.password_placeholder == "Password"
assert strings.reboot_tooltip == "Reboot"
assert strings.shutdown_tooltip == "Shut down"
def test_unknown_locale_falls_back_to_english(self) -> None:
strings = load_strings("fr")
assert strings.password_placeholder == "Password"
def test_returns_strings_dataclass(self) -> None:
strings = load_strings("de")
assert isinstance(strings, Strings)
def test_error_messages_are_present(self) -> None:
strings = load_strings("en")
assert strings.wrong_password
assert strings.auth_failed
assert strings.reboot_failed
assert strings.shutdown_failed
assert strings.no_session_selected
assert strings.multi_stage_unsupported
assert strings.invalid_session_command
assert strings.session_start_failed
assert strings.faillock_locked
def test_faillock_warning_template(self) -> None:
strings = load_strings("de")
# Template should accept an int for remaining attempts
result = strings.faillock_attempts_remaining.format(n=1)
assert "1" in result
def test_connection_error_is_generic(self) -> None:
strings = load_strings("en")
# Error messages should not contain format placeholders (no info leakage)
assert "{" not in strings.connection_error
assert "{" not in strings.socket_error