]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
add test and changelog for constant comparison folding 1105/head
authorDavid Lord <davidism@gmail.com>
Wed, 20 Nov 2019 14:55:16 +0000 (06:55 -0800)
committerDavid Lord <davidism@gmail.com>
Wed, 20 Nov 2019 14:55:16 +0000 (06:55 -0800)
CHANGES.rst
jinja2/nodes.py
tests/test_lexnparse.py

index 31aa480423910c7b3bc4ee59f4c3fbd9a3e4cc0a..f572e9adadecf29198cb11f539e21bfe71014789 100644 (file)
@@ -77,6 +77,10 @@ Unreleased
     :issue:`550`
 -   Use :func:`callable` to inject context at runtime for compatibility
     with Cython compiled functions. :pr:`1108`
+-   When chained comparisons of constants are evaluated at compile time,
+    the result follows Python's behavior of returning ``False`` if any
+    comparison returns ``False``, rather than only the last one.
+    :issue:`1102`
 
 
 Version 2.10.3
index 3f151f6d85ffea242b4066fb743d9033df0223b9..e46aa916778fbd1f29bb2fe16283aac5a10a3ce4 100644 (file)
@@ -768,15 +768,19 @@ class Compare(Expr):
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
         result = value = self.expr.as_const(eval_ctx)
+
         try:
             for op in self.ops:
                 new_value = op.expr.as_const(eval_ctx)
                 result = _cmpop_to_func[op.op](value, new_value)
+
                 if not result:
                     return False
+
                 value = new_value
         except Exception:
             raise Impossible()
+
         return result
 
 
index cc941eb53402d0575c43a596bb68055b70fd79e2..b5422824e2580e1834f449259e77066e28f17e80 100644 (file)
@@ -323,16 +323,39 @@ class TestSyntax(object):
         tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
         assert tmpl.render() == '[1, 2]foo'
 
-    def test_compare(self, env):
-        tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|'
-                               '{{ 2 == 2 }}|{{ 1 <= 1 }}')
-        assert tmpl.render() == 'True|True|True|True|True'
+    @pytest.mark.parametrize(
+        ("a", "op", "b"),
+        [
+            (1, ">", 0),
+            (1, ">=", 1),
+            (2, "<", 3),
+            (3, "<=", 4),
+            (4, "==", 4),
+            (4, "!=", 5),
+        ],
+    )
+    def test_compare(self, env, a, op, b):
+        t = env.from_string("{{ %d %s %d }}" % (a, op, b))
+        assert t.render() == "True"
 
     def test_compare_parens(self, env):
-        tmpl = env.from_string(
-            "{{ i*(j<5) }}"
-        )
-        assert tmpl.render(i=2, j=3) == '2'
+        t = env.from_string("{{ i * (j < 5) }}")
+        assert t.render(i=2, j=3) == "2"
+
+    @pytest.mark.parametrize(
+        ("src", "expect"),
+        [
+            ("{{ 4 < 2 < 3 }}", "False"),
+            ("{{ a < b < c }}", "False"),
+            ("{{ 4 > 2 > 3 }}", "False"),
+            ("{{ a > b > c }}", "False"),
+            ("{{ 4 > 2 < 3 }}", "True"),
+            ("{{ a > b < c }}", "True"),
+        ],
+    )
+    def test_compare_compound(self, env, src, expect):
+        t = env.from_string(src)
+        assert t.render(a=4, b=2, c=3) == expect
 
     def test_inop(self, env):
         tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}')