From f7f4f1c43275a3aa9473a848036fceafda22b773 Mon Sep 17 00:00:00 2001 From: Tomas R Date: Sun, 16 Feb 2025 13:05:01 +0100 Subject: [PATCH] gh-127488: Add tests for Tools/i18n/msgfmt.py (GH-127540) (cherry picked from commit 361083b84b0db975058b2d1f50dcbfd36f072caf) Co-authored-by: Tomas R. --- Lib/test/test_tools/msgfmt_data/fuzzy.mo | Bin 0 -> 28 bytes Lib/test/test_tools/msgfmt_data/fuzzy.po | 23 ++++ Lib/test/test_tools/msgfmt_data/general.mo | Bin 0 -> 728 bytes Lib/test/test_tools/msgfmt_data/general.po | 47 ++++++++ Lib/test/test_tools/test_msgfmt.py | 126 +++++++++++++++++++++ Makefile.pre.in | 1 + 6 files changed, 197 insertions(+) create mode 100644 Lib/test/test_tools/msgfmt_data/fuzzy.mo create mode 100644 Lib/test/test_tools/msgfmt_data/fuzzy.po create mode 100644 Lib/test/test_tools/msgfmt_data/general.mo create mode 100644 Lib/test/test_tools/msgfmt_data/general.po create mode 100644 Lib/test/test_tools/test_msgfmt.py diff --git a/Lib/test/test_tools/msgfmt_data/fuzzy.mo b/Lib/test/test_tools/msgfmt_data/fuzzy.mo new file mode 100644 index 0000000000000000000000000000000000000000..4b144831cf5f75c62f6e9446b91ce164bb3c8dee GIT binary patch literal 28 Tcmca7#4?ou3S@vZ2*UsXEKdQ# literal 0 HcmV?d00001 diff --git a/Lib/test/test_tools/msgfmt_data/fuzzy.po b/Lib/test/test_tools/msgfmt_data/fuzzy.po new file mode 100644 index 00000000000000..05e8354948ac0d --- /dev/null +++ b/Lib/test/test_tools/msgfmt_data/fuzzy.po @@ -0,0 +1,23 @@ +# Fuzzy translations are not written to the .mo file. +#, fuzzy +msgid "foo" +msgstr "bar" + +# comment +#, fuzzy +msgctxt "abc" +msgid "foo" +msgstr "bar" + +#, fuzzy +# comment +msgctxt "xyz" +msgid "foo" +msgstr "bar" + +#, fuzzy +msgctxt "abc" +msgid "One email sent." +msgid_plural "%d emails sent." +msgstr[0] "One email sent." +msgstr[1] "%d emails sent." diff --git a/Lib/test/test_tools/msgfmt_data/general.mo b/Lib/test/test_tools/msgfmt_data/general.mo new file mode 100644 index 0000000000000000000000000000000000000000..bc0683a62d0ddaecbc751b9a59eb1fe19bb7619c GIT binary patch literal 728 zcma)(L2uJA6vqQpLPUTj;5ZGdh|}bfR?}34GA(Me5s@@in@$2wZsHYBnN!&wY~#Rz zZ-B&^F90{b2oe_#@Dca~9QeB}l-scM(?9R|Z~NuFAGd1n9jt3$9TYbBXMM!?J@5%! z1z*4w@C~ei@8Aab32uX5!1~uNE&N;14bTC1k$--9asKsE-#~97{}y^3`VM*r`T=VF zpP}}>uTY0g@>(i6;m1srM005x&i!H$>Sb&_hgIcFm~u|f&TB4_{8cF=*TkJC>Rjh+ z#&vxjB`2j3^KGMqoX&F>Jz=l4PYhIb#B)QVf*x?CMJ0VQ2)a*#{g51l!%>v>-9ehs zuHwvKm-d+9K52QaE!y;GYnwFNzPG*UwLA|-I^-{fy=Ccp8U{m}q_h{1$Elx0o6pjI z=*CPNnkgoA$xNkuvNw)n(hri5biyQv;@zOv8-}CN4y\n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "foo" +msgstr "" + +msgid "bar" +msgstr "baz" + +msgctxt "abc" +msgid "foo" +msgstr "bar" + +# comment +msgctxt "xyz" +msgid "foo" +msgstr "bar" + +msgid "Multiline" +"string" +msgstr "Multiline" +"translation" + +msgid "\"escapes\"" +msgstr "\"translated\"" + +msgid "\n newlines \n" +msgstr "\n translated \n" + +msgid "One email sent." +msgid_plural "%d emails sent." +msgstr[0] "One email sent." +msgstr[1] "%d emails sent." + +msgctxt "abc" +msgid "One email sent." +msgid_plural "%d emails sent." +msgstr[0] "One email sent." +msgstr[1] "%d emails sent." diff --git a/Lib/test/test_tools/test_msgfmt.py b/Lib/test/test_tools/test_msgfmt.py new file mode 100644 index 00000000000000..e3e3035c4f4395 --- /dev/null +++ b/Lib/test/test_tools/test_msgfmt.py @@ -0,0 +1,126 @@ +"""Tests for the Tools/i18n/msgfmt.py tool.""" + +import sys +import unittest +from gettext import GNUTranslations +from pathlib import Path + +from test.support.os_helper import temp_cwd +from test.support.script_helper import assert_python_failure, assert_python_ok +from test.test_tools import skip_if_missing, toolsdir + + +skip_if_missing('i18n') + +data_dir = (Path(__file__).parent / 'msgfmt_data').resolve() +script_dir = Path(toolsdir) / 'i18n' +msgfmt = script_dir / 'msgfmt.py' + + +def compile_messages(po_file, mo_file): + assert_python_ok(msgfmt, '-o', mo_file, po_file) + + +class CompilationTest(unittest.TestCase): + + def test_compilation(self): + self.maxDiff = None + with temp_cwd(): + for po_file in data_dir.glob('*.po'): + with self.subTest(po_file=po_file): + mo_file = po_file.with_suffix('.mo') + with open(mo_file, 'rb') as f: + expected = GNUTranslations(f) + + tmp_mo_file = mo_file.name + compile_messages(po_file, tmp_mo_file) + with open(tmp_mo_file, 'rb') as f: + actual = GNUTranslations(f) + + self.assertDictEqual(actual._catalog, expected._catalog) + + def test_invalid_msgid_plural(self): + with temp_cwd(): + Path('invalid.po').write_text('''\ +msgid_plural "plural" +msgstr[0] "singular" +''') + + res = assert_python_failure(msgfmt, 'invalid.po') + err = res.err.decode('utf-8') + self.assertIn('msgid_plural not preceded by msgid', err) + + def test_plural_without_msgid_plural(self): + with temp_cwd(): + Path('invalid.po').write_text('''\ +msgid "foo" +msgstr[0] "bar" +''') + + res = assert_python_failure(msgfmt, 'invalid.po') + err = res.err.decode('utf-8') + self.assertIn('plural without msgid_plural', err) + + def test_indexed_msgstr_without_msgid_plural(self): + with temp_cwd(): + Path('invalid.po').write_text('''\ +msgid "foo" +msgid_plural "foos" +msgstr "bar" +''') + + res = assert_python_failure(msgfmt, 'invalid.po') + err = res.err.decode('utf-8') + self.assertIn('indexed msgstr required for plural', err) + + def test_generic_syntax_error(self): + with temp_cwd(): + Path('invalid.po').write_text('''\ +"foo" +''') + + res = assert_python_failure(msgfmt, 'invalid.po') + err = res.err.decode('utf-8') + self.assertIn('Syntax error', err) + +class CLITest(unittest.TestCase): + + def test_help(self): + for option in ('--help', '-h'): + res = assert_python_ok(msgfmt, option) + err = res.err.decode('utf-8') + self.assertIn('Generate binary message catalog from textual translation description.', err) + + def test_version(self): + for option in ('--version', '-V'): + res = assert_python_ok(msgfmt, option) + out = res.out.decode('utf-8').strip() + self.assertEqual('msgfmt.py 1.2', out) + + def test_invalid_option(self): + res = assert_python_failure(msgfmt, '--invalid-option') + err = res.err.decode('utf-8') + self.assertIn('Generate binary message catalog from textual translation description.', err) + self.assertIn('option --invalid-option not recognized', err) + + def test_no_input_file(self): + res = assert_python_ok(msgfmt) + err = res.err.decode('utf-8').replace('\r\n', '\n') + self.assertIn('No input file given\n' + "Try `msgfmt --help' for more information.", err) + + def test_nonexistent_file(self): + assert_python_failure(msgfmt, 'nonexistent.po') + + +def update_catalog_snapshots(): + for po_file in data_dir.glob('*.po'): + mo_file = po_file.with_suffix('.mo') + compile_messages(po_file, mo_file) + + +if __name__ == '__main__': + if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': + update_catalog_snapshots() + sys.exit(0) + unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index 689f33d8ffe90a..c6943ea8231c51 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2237,6 +2237,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_tomllib/data/valid/multiline-basic-str \ test/test_tools \ test/test_tools/i18n_data \ + test/test_tools/msgfmt_data \ test/test_ttk \ test/test_unittest \ test/test_unittest/testmock \