]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Increase test coverage of the `python_format` checker (#1176)
authorTomas R. <tomas.roun8@gmail.com>
Fri, 31 Jan 2025 13:23:34 +0000 (14:23 +0100)
committerGitHub <noreply@github.com>
Fri, 31 Jan 2025 13:23:34 +0000 (15:23 +0200)
babel/messages/checkers.py
tests/messages/test_checkers.py

index 2889b4e6c0d3a5c6c698824643930de11ed116e4..79b3a6faa8549b4a7813513458199eaa3c9baccd 100644 (file)
@@ -65,9 +65,6 @@ def _validate_format(format: str, alternative: str) -> None:
     arguments are not interchangeable as `alternative` may contain less
     placeholders if `format` uses named placeholders.
 
-    The behavior of this function is undefined if the string does not use
-    string formatting.
-
     If the string formatting of `alternative` is compatible to `format` the
     function returns `None`, otherwise a `TranslationError` is raised.
 
@@ -121,6 +118,9 @@ def _validate_format(format: str, alternative: str) -> None:
 
     a, b = map(_parse, (format, alternative))
 
+    if not a:
+        return
+
     # now check if both strings are positional or named
     a_positional, b_positional = map(_check_positional, (a, b))
     if a_positional and not b_positional and not b:
index 6d87b742e120fdbe39c5619bc35a50f0cd5969a7..586347cff401f7f98d5d7779bc03c3b1009e41f2 100644 (file)
@@ -14,10 +14,14 @@ import unittest
 from datetime import datetime
 from io import BytesIO
 
+import pytest
+
 from babel import __version__ as VERSION
 from babel.core import Locale, UnknownLocaleError
 from babel.dates import format_datetime
-from babel.messages import checkers
+from babel.messages import Message, checkers
+from babel.messages.catalog import TranslationError
+from babel.messages.checkers import _validate_format, python_format
 from babel.messages.plurals import PLURALS
 from babel.messages.pofile import read_po
 from babel.util import LOCALTZ
@@ -325,3 +329,59 @@ msgstr[4] ""
             catalog = read_po(BytesIO(po_file), _locale)
             message = catalog['foobar']
             checkers.num_plurals(catalog, message)
+
+
+class TestPythonFormat:
+    @pytest.mark.parametrize(('msgid', 'msgstr'), [
+        ('foo %s', 'foo'),
+        (('foo %s', 'bar'), ('foo', 'bar')),
+        (('foo', 'bar %s'), ('foo', 'bar')),
+        (('foo %s', 'bar'), ('foo')),
+    ])
+    def test_python_format_invalid(self, msgid, msgstr):
+        msg = Message(msgid, msgstr)
+        with pytest.raises(TranslationError):
+            python_format(None, msg)
+
+    @pytest.mark.parametrize(('msgid', 'msgstr'), [
+        ('foo', 'foo'),
+        ('foo', 'foo %s'),
+        (('foo %s', 'bar %d'), ('foo %s', 'bar %d')),
+        (('foo %s', 'bar %d'), ('foo %s', 'bar %d', 'baz')),
+        (('foo', 'bar %s'), ('foo')),
+    ])
+    def test_python_format_valid(self, msgid, msgstr):
+        msg = Message(msgid, msgstr)
+        python_format(None, msg)
+
+    @pytest.mark.parametrize(('msgid', 'msgstr', 'error'), [
+        ('%s %(foo)s', '%s %(foo)s', 'format string mixes positional and named placeholders'),
+        ('foo %s', 'foo', 'placeholders are incompatible'),
+        ('%s', '%(foo)s', 'the format strings are of different kinds'),
+        ('%s', '%s %d', 'positional format placeholders are unbalanced'),
+        ('%s', '%d', "incompatible format for placeholder 1: 's' and 'd' are not compatible"),
+        ('%s %s %d', '%s %s %s', "incompatible format for placeholder 3: 'd' and 's' are not compatible"),
+        ('%(foo)s', '%(bar)s', "unknown named placeholder 'bar'"),
+        ('%(foo)s', '%(bar)d', "unknown named placeholder 'bar'"),
+        ('%(foo)s', '%(foo)d', "incompatible format for placeholder 'foo': 'd' and 's' are not compatible"),
+    ])
+    def test__validate_format_invalid(self, msgid, msgstr, error):
+        with pytest.raises(TranslationError, match=error):
+            _validate_format(msgid, msgstr)
+
+    @pytest.mark.parametrize(('msgid', 'msgstr'), [
+        ('foo', 'foo'),
+        ('foo', 'foo %s'),
+        ('%s foo', 'foo %s'),
+        ('%i', '%d'),
+        ('%d', '%u'),
+        ('%x', '%X'),
+        ('%f', '%F'),
+        ('%F', '%g'),
+        ('%g', '%G'),
+        ('%(foo)s', 'foo'),
+        ('%(foo)s', '%(foo)s %(foo)s'),
+        ('%(bar)s foo %(n)d', '%(n)d foo %(bar)s'),
+    ])
+    def test__validate_format_valid(self, msgid, msgstr):
+        _validate_format(msgid, msgstr)