]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Add more strict type tests 824/head
authorDag Wieers <dag@wieers.com>
Sat, 17 Mar 2018 03:00:11 +0000 (04:00 +0100)
committerDavid Lord <davidism@gmail.com>
Thu, 10 Oct 2019 03:02:28 +0000 (20:02 -0700)
This PR adds a few more type-related tests.

- boolean
    Testing of an object is a boolean required 2 tests.

- false
    Make this similar to testing none value

- true
    Make this similar to testing none value

- integer
    The existing 'number' test does not make a distinction between
    integer, float or even booleans

- float
    The existing 'number' test does not make a distinction between
    integer, float or even booleans

CHANGES.rst
jinja2/tests.py
tests/test_tests.py

index 35673a0a720b56c5b91242a1e4f6d9df2ecc096f..2c1e2863291583e5e017c1bb9eb50b364e241f57 100644 (file)
@@ -32,6 +32,8 @@ Unreleased
 -   Parentheses around comparisons are preserved, so
     ``{{ 2 * (3 < 5) }}`` outputs "2" instead of "False".
     :issue:`755`, :pr:`938`
+-   Add new ``boolean``, ``false``, ``true``, ``integer`` and ``float``
+    tests. :pr:`824`
 
 
 Version 2.10.3
index bc99d66c83d6161f004d6000dd0081dbe429e750..87f9c0c2d9d2eb91933d74304a692c1442d7b5e0 100644 (file)
@@ -63,6 +63,48 @@ def test_none(value):
     return value is None
 
 
+def test_boolean(value):
+    """Return true if the object is a boolean value.
+
+    .. versionadded:: 2.11
+    """
+    return value is True or value is False
+
+
+def test_false(value):
+    """Return true if the object is False.
+
+    .. versionadded:: 2.11
+    """
+    return value is False
+
+
+def test_true(value):
+    """Return true if the object is True.
+
+    .. versionadded:: 2.11
+    """
+    return value is True
+
+
+# NOTE: The existing Jinja2 'number' test matches booleans and floats
+def test_integer(value):
+    """Return true if the object is an integer.
+
+    .. versionadded:: 2.11
+    """
+    return isinstance(value, integer_types) and value is not True and value is not False
+
+
+# NOTE: The existing Jinja2 'number' test matches booleans and integers
+def test_float(value):
+    """Return true if the object is a float.
+
+    .. versionadded:: 2.11
+    """
+    return isinstance(value, float)
+
+
 def test_lower(value):
     """Return true if the variable is lowercased."""
     return text_type(value).islower()
@@ -145,6 +187,11 @@ TESTS = {
     'defined':          test_defined,
     'undefined':        test_undefined,
     'none':             test_none,
+    'boolean':          test_boolean,
+    'false':            test_false,
+    'true':             test_true,
+    'integer':          test_integer,
+    'float':            test_float,
     'lower':            test_lower,
     'upper':            test_upper,
     'string':           test_string,
index 84df5ea7577495ea5c76f29dfcd1416248d2b2e0..a596022c5e3cc7ead78352089b07ac19abbb49e8 100644 (file)
@@ -12,6 +12,8 @@ import pytest
 
 from jinja2 import Markup, Environment
 
+class MyDict(dict):
+    pass
 
 @pytest.mark.test_tests
 class TestTestsCase(object):
@@ -33,45 +35,101 @@ class TestTestsCase(object):
         tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''')
         assert tmpl.render() == 'True|False'
 
-    def test_typechecks(self, env):
-        tmpl = env.from_string('''
-            {{ 42 is undefined }}
-            {{ 42 is defined }}
-            {{ 42 is none }}
-            {{ none is none }}
-            {{ 42 is number }}
-            {{ 42 is string }}
-            {{ "foo" is string }}
-            {{ "foo" is sequence }}
-            {{ [1] is sequence }}
-            {{ range is callable }}
-            {{ 42 is callable }}
-            {{ range(5) is iterable }}
-            {{ {} is mapping }}
-            {{ mydict is mapping }}
-            {{ [] is mapping }}
-            {{ 10 is number }}
-            {{ (10 ** 100) is number }}
-            {{ 3.14159 is number }}
-            {{ complex is number }}
-        ''')
-
-        class MyDict(dict):
-            pass
-
-        assert tmpl.render(mydict=MyDict(), complex=complex(1, 2)).split() == [
-            'False', 'True', 'False', 'True', 'True', 'False',
-            'True', 'True', 'True', 'True', 'False', 'True',
-            'True', 'True', 'False', 'True', 'True', 'True', 'True'
-        ]
-
-    def test_sequence(self, env):
-        tmpl = env.from_string(
-            '{{ [1, 2, 3] is sequence }}|'
-            '{{ "foo" is sequence }}|'
-            '{{ 42 is sequence }}'
-        )
-        assert tmpl.render() == 'True|True|False'
+    # Test type checks
+    @pytest.mark.parametrize('op,expect', (
+        ('none is none', True),
+        ('false is none', False),
+        ('true is none', False),
+        ('42 is none', False),
+
+        ('none is true', False),
+        ('false is true', False),
+        ('true is true', True),
+        ('0 is true', False),
+        ('1 is true', False),
+        ('42 is true', False),
+
+        ('none is false', False),
+        ('false is false', True),
+        ('true is false', False),
+        ('0 is false', False),
+        ('1 is false', False),
+        ('42 is false', False),
+
+        ('none is boolean', False),
+        ('false is boolean', True),
+        ('true is boolean', True),
+        ('0 is boolean', False),
+        ('1 is boolean', False),
+        ('42 is boolean', False),
+        ('0.0 is boolean', False),
+        ('1.0 is boolean', False),
+        ('3.14159 is boolean', False),
+
+        ('none is integer', False),
+        ('false is integer', False),
+        ('true is integer', False),
+        ('42 is integer', True),
+        ('3.14159 is integer', False),
+        ('(10 ** 100) is integer', True),
+
+        ('none is float', False),
+        ('false is float', False),
+        ('true is float', False),
+        ('42 is float', False),
+        ('4.2 is float', True),
+        ('(10 ** 100) is float', False),
+
+        ('none is number', False),
+        ('false is number', True),
+        ('true is number', True),
+        ('42 is number', True),
+        ('3.14159 is number', True),
+        ('complex is number', True),
+        ('(10 ** 100) is number', True),
+
+        ('none is string', False),
+        ('false is string', False),
+        ('true is string', False),
+        ('42 is string', False),
+        ('"foo" is string', True),
+
+        ('none is sequence', False),
+        ('false is sequence', False),
+        ('42 is sequence', False),
+        ('"foo" is sequence', True),
+        ('[] is sequence', True),
+        ('[1, 2, 3] is sequence', True),
+        ('{} is sequence', True),
+
+        ('none is mapping', False),
+        ('false is mapping', False),
+        ('42 is mapping', False),
+        ('"foo" is mapping', False),
+        ('[] is mapping', False),
+        ('{} is mapping', True),
+        ('mydict is mapping', True),
+
+        ('none is iterable', False),
+        ('false is iterable', False),
+        ('42 is iterable', False),
+        ('"foo" is iterable', True),
+        ('[] is iterable', True),
+        ('{} is iterable', True),
+        ('range(5) is iterable', True),
+
+        ('none is callable', False),
+        ('false is callable', False),
+        ('42 is callable', False),
+        ('"foo" is callable', False),
+        ('[] is callable', False),
+        ('{} is callable', False),
+        ('range is callable', True),
+    ))
+    def test_types(self, env, op, expect):
+        t = env.from_string('{{{{ {op} }}}}'.format(op=op))
+        assert t.render(mydict=MyDict(), complex=complex(1, 2)) == str(expect)
+
 
     def test_upper(self, env):
         tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')