1import pytest
2
3from markupsafe import Markup
4
5
6def test_adding(escape):
7    unsafe = '<script type="application/x-some-script">alert("foo");</script>'
8    safe = Markup("<em>username</em>")
9    assert unsafe + safe == str(escape(unsafe)) + str(safe)
10
11
12@pytest.mark.parametrize(
13    ("template", "data", "expect"),
14    (
15        ("<em>%s</em>", "<bad user>", "<em>&lt;bad user&gt;</em>"),
16        (
17            "<em>%(username)s</em>",
18            {"username": "<bad user>"},
19            "<em>&lt;bad user&gt;</em>",
20        ),
21        ("%i", 3.14, "3"),
22        ("%.2f", 3.14, "3.14"),
23    ),
24)
25def test_string_interpolation(template, data, expect):
26    assert Markup(template) % data == expect
27
28
29def test_type_behavior():
30    assert type(Markup("foo") + "bar") is Markup
31    x = Markup("foo")
32    assert x.__html__() is x
33
34
35def test_html_interop():
36    class Foo:
37        def __html__(self):
38            return "<em>awesome</em>"
39
40        def __str__(self):
41            return "awesome"
42
43    assert Markup(Foo()) == "<em>awesome</em>"
44    result = Markup("<strong>%s</strong>") % Foo()
45    assert result == "<strong><em>awesome</em></strong>"
46
47
48def test_tuple_interpol():
49    result = Markup("<em>%s:%s</em>") % ("<foo>", "<bar>")
50    expect = Markup("<em>&lt;foo&gt;:&lt;bar&gt;</em>")
51    assert result == expect
52
53
54def test_dict_interpol():
55    result = Markup("<em>%(foo)s</em>") % {"foo": "<foo>"}
56    expect = Markup("<em>&lt;foo&gt;</em>")
57    assert result == expect
58
59    result = Markup("<em>%(foo)s:%(bar)s</em>") % {"foo": "<foo>", "bar": "<bar>"}
60    expect = Markup("<em>&lt;foo&gt;:&lt;bar&gt;</em>")
61    assert result == expect
62
63
64def test_escaping(escape):
65    assert escape("\"<>&'") == "&#34;&lt;&gt;&amp;&#39;"
66    assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
67
68
69def test_unescape():
70    assert Markup("&lt;test&gt;").unescape() == "<test>"
71
72    result = Markup("jack & tavi are cooler than mike &amp; russ").unescape()
73    expect = "jack & tavi are cooler than mike & russ"
74    assert result == expect
75
76    original = "&foo&#x3b;"
77    once = Markup(original).unescape()
78    twice = Markup(once).unescape()
79    expect = "&foo;"
80    assert once == expect
81    assert twice == expect
82
83
84def test_format():
85    result = Markup("<em>{awesome}</em>").format(awesome="<awesome>")
86    assert result == "<em>&lt;awesome&gt;</em>"
87
88    result = Markup("{0[1][bar]}").format([0, {"bar": "<bar/>"}])
89    assert result == "&lt;bar/&gt;"
90
91    result = Markup("{0[1][bar]}").format([0, {"bar": Markup("<bar/>")}])
92    assert result == "<bar/>"
93
94
95def test_formatting_empty():
96    formatted = Markup("{}").format(0)
97    assert formatted == Markup("0")
98
99
100def test_custom_formatting():
101    class HasHTMLOnly:
102        def __html__(self):
103            return Markup("<foo>")
104
105    class HasHTMLAndFormat:
106        def __html__(self):
107            return Markup("<foo>")
108
109        def __html_format__(self, spec):
110            return Markup("<FORMAT>")
111
112    assert Markup("{0}").format(HasHTMLOnly()) == Markup("<foo>")
113    assert Markup("{0}").format(HasHTMLAndFormat()) == Markup("<FORMAT>")
114
115
116def test_complex_custom_formatting():
117    class User:
118        def __init__(self, id, username):
119            self.id = id
120            self.username = username
121
122        def __html_format__(self, format_spec):
123            if format_spec == "link":
124                return Markup('<a href="/user/{0}">{1}</a>').format(
125                    self.id, self.__html__()
126                )
127            elif format_spec:
128                raise ValueError("Invalid format spec")
129
130            return self.__html__()
131
132        def __html__(self):
133            return Markup("<span class=user>{0}</span>").format(self.username)
134
135    user = User(1, "foo")
136    result = Markup("<p>User: {0:link}").format(user)
137    expect = Markup('<p>User: <a href="/user/1"><span class=user>foo</span></a>')
138    assert result == expect
139
140
141def test_formatting_with_objects():
142    class Stringable:
143        def __str__(self):
144            return "строка"
145
146    assert Markup("{s}").format(s=Stringable()) == Markup("строка")
147
148
149def test_escape_silent(escape, escape_silent):
150    assert escape_silent(None) == Markup()
151    assert escape(None) == Markup(None)
152    assert escape_silent("<foo>") == Markup("&lt;foo&gt;")
153
154
155def test_splitting():
156    expect = [Markup("a"), Markup("b")]
157    assert Markup("a b").split() == expect
158    assert Markup("a b").rsplit() == expect
159    assert Markup("a\nb").splitlines() == expect
160
161
162def test_mul():
163    assert Markup("a") * 3 == Markup("aaa")
164
165
166def test_escape_return_type(escape):
167    assert isinstance(escape("a"), Markup)
168    assert isinstance(escape(Markup("a")), Markup)
169
170    class Foo:
171        def __html__(self):
172            return "<strong>Foo</strong>"
173
174    assert isinstance(escape(Foo()), Markup)
175
176
177def test_soft_str(soft_str):
178    assert type(soft_str("")) is str
179    assert type(soft_str(Markup())) is Markup
180    assert type(soft_str(15)) is str
181
182
183def test_soft_unicode_deprecated(soft_unicode):
184    with pytest.warns(DeprecationWarning):
185        assert type(soft_unicode(Markup())) is Markup
186