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