1import math 2 3import pytest 4 5from jinja2.exceptions import UndefinedError 6from jinja2.nativetypes import NativeEnvironment 7from jinja2.nativetypes import NativeTemplate 8from jinja2.runtime import Undefined 9 10 11@pytest.fixture 12def env(): 13 return NativeEnvironment() 14 15 16def test_is_defined_native_return(env): 17 t = env.from_string("{{ missing is defined }}") 18 assert not t.render() 19 20 21def test_undefined_native_return(env): 22 t = env.from_string("{{ missing }}") 23 assert isinstance(t.render(), Undefined) 24 25 26def test_adding_undefined_native_return(env): 27 t = env.from_string("{{ 3 + missing }}") 28 29 with pytest.raises(UndefinedError): 30 t.render() 31 32 33def test_cast_int(env): 34 t = env.from_string("{{ value|int }}") 35 result = t.render(value="3") 36 assert isinstance(result, int) 37 assert result == 3 38 39 40def test_list_add(env): 41 t = env.from_string("{{ a + b }}") 42 result = t.render(a=["a", "b"], b=["c", "d"]) 43 assert isinstance(result, list) 44 assert result == ["a", "b", "c", "d"] 45 46 47def test_multi_expression_add(env): 48 t = env.from_string("{{ a }} + {{ b }}") 49 result = t.render(a=["a", "b"], b=["c", "d"]) 50 assert not isinstance(result, list) 51 assert result == "['a', 'b'] + ['c', 'd']" 52 53 54def test_loops(env): 55 t = env.from_string("{% for x in value %}{{ x }}{% endfor %}") 56 result = t.render(value=["a", "b", "c", "d"]) 57 assert isinstance(result, str) 58 assert result == "abcd" 59 60 61def test_loops_with_ints(env): 62 t = env.from_string("{% for x in value %}{{ x }}{% endfor %}") 63 result = t.render(value=[1, 2, 3, 4]) 64 assert isinstance(result, int) 65 assert result == 1234 66 67 68def test_loop_look_alike(env): 69 t = env.from_string("{% for x in value %}{{ x }}{% endfor %}") 70 result = t.render(value=[1]) 71 assert isinstance(result, int) 72 assert result == 1 73 74 75@pytest.mark.parametrize( 76 ("source", "expect"), 77 ( 78 ("{{ value }}", True), 79 ("{{ value }}", False), 80 ("{{ 1 == 1 }}", True), 81 ("{{ 2 + 2 == 5 }}", False), 82 ("{{ None is none }}", True), 83 ("{{ '' == None }}", False), 84 ), 85) 86def test_booleans(env, source, expect): 87 t = env.from_string(source) 88 result = t.render(value=expect) 89 assert isinstance(result, bool) 90 assert result is expect 91 92 93def test_variable_dunder(env): 94 t = env.from_string("{{ x.__class__ }}") 95 result = t.render(x=True) 96 assert isinstance(result, type) 97 98 99def test_constant_dunder(env): 100 t = env.from_string("{{ true.__class__ }}") 101 result = t.render() 102 assert isinstance(result, type) 103 104 105def test_constant_dunder_to_string(env): 106 t = env.from_string("{{ true.__class__|string }}") 107 result = t.render() 108 assert not isinstance(result, type) 109 assert result in {"<type 'bool'>", "<class 'bool'>"} 110 111 112def test_string_literal_var(env): 113 t = env.from_string("[{{ 'all' }}]") 114 result = t.render() 115 assert isinstance(result, str) 116 assert result == "[all]" 117 118 119def test_string_top_level(env): 120 t = env.from_string("'Jinja'") 121 result = t.render() 122 assert result == "Jinja" 123 124 125def test_tuple_of_variable_strings(env): 126 t = env.from_string("'{{ a }}', 'data', '{{ b }}', b'{{ c }}'") 127 result = t.render(a=1, b=2, c="bytes") 128 assert isinstance(result, tuple) 129 assert result == ("1", "data", "2", b"bytes") 130 131 132def test_concat_strings_with_quotes(env): 133 t = env.from_string("--host='{{ host }}' --user \"{{ user }}\"") 134 result = t.render(host="localhost", user="Jinja") 135 assert result == "--host='localhost' --user \"Jinja\"" 136 137 138def test_no_intermediate_eval(env): 139 t = env.from_string("0.000{{ a }}") 140 result = t.render(a=7) 141 assert isinstance(result, float) 142 # If intermediate eval happened, 0.000 would render 0.0, then 7 143 # would be appended, resulting in 0.07. 144 assert math.isclose(result, 0.0007) 145 146 147def test_spontaneous_env(): 148 t = NativeTemplate("{{ true }}") 149 assert isinstance(t.environment, NativeEnvironment) 150