Reflect the current year in all TechnoLibre license headers across script/, test/, and docker/. Generated by Claude Code 2.1.74 model claude-sonnet-4-6 Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
244 lines
7.4 KiB
Python
244 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from script.todo import todo_i18n
|
|
|
|
|
|
class TestTranslations(unittest.TestCase):
|
|
"""Test TRANSLATIONS dictionary integrity."""
|
|
|
|
def test_all_entries_have_fr_and_en(self):
|
|
for key, entry in todo_i18n.TRANSLATIONS.items():
|
|
self.assertIn("fr", entry, f"Key '{key}' missing 'fr' translation")
|
|
self.assertIn("en", entry, f"Key '{key}' missing 'en' translation")
|
|
|
|
def test_no_empty_translations(self):
|
|
for key, entry in todo_i18n.TRANSLATIONS.items():
|
|
for lang in ("fr", "en"):
|
|
self.assertTrue(
|
|
len(entry[lang]) > 0,
|
|
f"Key '{key}' has empty '{lang}' translation",
|
|
)
|
|
|
|
def test_translations_not_empty(self):
|
|
self.assertGreater(len(todo_i18n.TRANSLATIONS), 0)
|
|
|
|
|
|
class TestT(unittest.TestCase):
|
|
"""Test t() translation function."""
|
|
|
|
def setUp(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def tearDown(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def test_returns_french_when_lang_fr(self):
|
|
todo_i18n.set_lang("fr")
|
|
result = todo_i18n.t("menu_quit")
|
|
self.assertEqual(result, "Quitter")
|
|
|
|
def test_returns_english_when_lang_en(self):
|
|
todo_i18n.set_lang("en")
|
|
result = todo_i18n.t("menu_quit")
|
|
self.assertEqual(result, "Quit")
|
|
|
|
def test_unknown_key_returns_key(self):
|
|
todo_i18n.set_lang("fr")
|
|
result = todo_i18n.t("nonexistent_key_xyz")
|
|
self.assertEqual(result, "nonexistent_key_xyz")
|
|
|
|
def test_fallback_to_fr_if_lang_missing(self):
|
|
todo_i18n.set_lang("de")
|
|
result = todo_i18n.t("menu_quit")
|
|
self.assertEqual(result, "Quitter")
|
|
|
|
|
|
class TestGetLang(unittest.TestCase):
|
|
"""Test get_lang() function."""
|
|
|
|
def setUp(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def tearDown(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def test_returns_cached_lang(self):
|
|
todo_i18n._current_lang = "en"
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "en")
|
|
|
|
def test_reads_from_env_var_sh(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write('EL_LANG="en"\n')
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "en")
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_reads_unquoted_lang(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write("EL_LANG=fr\n")
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "fr")
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_env_variable_fallback(self):
|
|
with patch.object(
|
|
todo_i18n,
|
|
"ENV_VAR_FILE",
|
|
"/nonexistent/path",
|
|
), patch.dict(os.environ, {"EL_LANG": "en"}):
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "en")
|
|
|
|
def test_default_is_fr(self):
|
|
with patch.object(
|
|
todo_i18n,
|
|
"ENV_VAR_FILE",
|
|
"/nonexistent/path",
|
|
), patch.dict(os.environ, {}, clear=True):
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "fr")
|
|
|
|
def test_invalid_lang_in_file_falls_through(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write('EL_LANG="de"\n')
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
), patch.dict(os.environ, {}, clear=True):
|
|
result = todo_i18n.get_lang()
|
|
self.assertEqual(result, "fr")
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
|
|
class TestSetLang(unittest.TestCase):
|
|
"""Test set_lang() function."""
|
|
|
|
def setUp(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def tearDown(self):
|
|
todo_i18n._current_lang = None
|
|
|
|
def test_sets_current_lang(self):
|
|
todo_i18n.set_lang("en")
|
|
self.assertEqual(todo_i18n._current_lang, "en")
|
|
|
|
def test_persists_to_file_update(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write('EL_LANG="fr"\nOTHER=value\n')
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
todo_i18n.set_lang("en")
|
|
with open(f.name) as rf:
|
|
content = rf.read()
|
|
self.assertIn('EL_LANG="en"', content)
|
|
self.assertIn("OTHER=value", content)
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_persists_to_file_append(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write("SOME_VAR=123\n")
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
todo_i18n.set_lang("en")
|
|
with open(f.name) as rf:
|
|
content = rf.read()
|
|
self.assertIn('EL_LANG="en"', content)
|
|
self.assertIn("SOME_VAR=123", content)
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_nonexistent_file_no_crash(self):
|
|
with patch.object(
|
|
todo_i18n,
|
|
"ENV_VAR_FILE",
|
|
"/nonexistent/path",
|
|
):
|
|
todo_i18n.set_lang("en")
|
|
self.assertEqual(todo_i18n._current_lang, "en")
|
|
|
|
|
|
class TestLangIsConfigured(unittest.TestCase):
|
|
"""Test lang_is_configured() function."""
|
|
|
|
def test_returns_true_when_configured(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write('EL_LANG="fr"\n')
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
result = todo_i18n.lang_is_configured()
|
|
self.assertTrue(result)
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_returns_false_when_not_configured(self):
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".sh", delete=False
|
|
) as f:
|
|
f.write("SOME_VAR=123\n")
|
|
f.flush()
|
|
try:
|
|
with patch.object(
|
|
todo_i18n, "ENV_VAR_FILE", f.name
|
|
):
|
|
result = todo_i18n.lang_is_configured()
|
|
self.assertFalse(result)
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
def test_returns_false_when_file_missing(self):
|
|
with patch.object(
|
|
todo_i18n,
|
|
"ENV_VAR_FILE",
|
|
"/nonexistent/path",
|
|
):
|
|
result = todo_i18n.lang_is_configured()
|
|
self.assertFalse(result)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|