1
from __future__ import annotations
4
from datetime import datetime
8
from werkzeug import Request
9
from werkzeug import utils
10
from werkzeug.datastructures import Headers
11
from werkzeug.http import http_date
12
from werkzeug.http import parse_date
13
from werkzeug.test import Client
14
from werkzeug.test import EnvironBuilder
15
from werkzeug.wrappers import Response
18
@pytest.mark.parametrize(
19
("url", "code", "expect"),
21
("http://example.com", None, "http://example.com"),
22
("/füübär", 305, "/f%C3%BC%C3%BCb%C3%A4r"),
23
("http://☃.example.com/", 307, "http://xn--n3h.example.com/"),
24
("itms-services://?url=abc", None, "itms-services://?url=abc"),
27
def test_redirect(url: str, code: int | None, expect: str) -> None:
28
environ = EnvironBuilder().get_environ()
31
resp = utils.redirect(url)
32
assert resp.status_code == 302
34
resp = utils.redirect(url, code)
35
assert resp.status_code == code
37
assert resp.headers["Location"] == url
38
assert resp.get_wsgi_headers(environ)["Location"] == expect
39
assert resp.get_data(as_text=True).count(url) == 2
42
def test_redirect_xss():
43
location = 'http://example.com/?xss="><script>alert(1)</script>'
44
resp = utils.redirect(location)
45
assert b"<script>alert(1)</script>" not in resp.get_data()
47
location = 'http://example.com/?xss="onmouseover="alert(1)'
48
resp = utils.redirect(location)
50
b'href="http://example.com/?xss="onmouseover="alert(1)"' not in resp.get_data()
54
def test_redirect_with_custom_response_class():
55
class MyResponse(Response):
58
location = "http://example.com/redirect"
59
resp = utils.redirect(location, Response=MyResponse)
61
assert isinstance(resp, MyResponse)
62
assert resp.headers["Location"] == location
65
def test_cached_property():
73
prop = utils.cached_property(prop)
88
prop = utils.cached_property(_prop, name="prop")
98
def test_can_set_cached_property():
100
@utils.cached_property
102
return "cached_property return value"
106
assert a._prop == "value"
109
def test_invalidate_cached_property():
113
@utils.cached_property
135
def test_inspect_treats_cached_property_as_property():
137
@utils.cached_property
139
return "cached_property return value"
141
attrs = inspect.classify_class_attrs(A)
143
if attr.name == "_prop":
145
assert attr.kind == "property"
148
def test_environ_property():
150
environ = {"string": "abc", "number": "42"}
152
string = utils.environ_property("string")
153
missing = utils.environ_property("missing", "spam")
154
read_only = utils.environ_property("number")
155
number = utils.environ_property("number", load_func=int)
156
broken_number = utils.environ_property("broken_number", load_func=int)
157
date = utils.environ_property(
158
"date", None, parse_date, http_date, read_only=False
160
foo = utils.environ_property("foo")
163
assert a.string == "abc"
164
assert a.missing == "spam"
167
a.read_only = "something"
169
pytest.raises(AttributeError, test_assign)
170
assert a.number == 42
171
assert a.broken_number is None
172
assert a.date is None
173
a.date = datetime(2008, 1, 22, 10, 0, 0, 0)
174
assert a.environ["date"] == "Tue, 22 Jan 2008 10:00:00 GMT"
177
def test_import_string():
178
from datetime import date
180
from werkzeug.debug import DebuggedApplication
182
assert utils.import_string("datetime.date") is date
183
assert utils.import_string("datetime.date") is date
184
assert utils.import_string("datetime:date") is date
185
assert utils.import_string("XXXXXXXXXXXX", True) is None
186
assert utils.import_string("datetime.XXXXXXXXXXXX", True) is None
188
utils.import_string("werkzeug.debug.DebuggedApplication") is DebuggedApplication
190
pytest.raises(ImportError, utils.import_string, "XXXXXXXXXXXXXXXX")
191
pytest.raises(ImportError, utils.import_string, "datetime.XXXXXXXXXX")
194
def test_import_string_provides_traceback(tmpdir, monkeypatch):
195
monkeypatch.syspath_prepend(str(tmpdir))
197
dir_a = tmpdir.mkdir("a")
198
dir_b = tmpdir.mkdir("b")
200
dir_a.join("__init__.py").write("")
201
dir_b.join("__init__.py").write("")
203
dir_a.join("aa.py").write("from b import bb")
204
dir_b.join("bb.py").write("from os import a_typo")
207
with pytest.raises(ImportError) as baz_exc:
208
utils.import_string("a.aa")
209
traceback = "".join(str(line) for line in baz_exc.traceback)
210
assert "bb.py':1" in traceback
211
assert "from os import a_typo" in traceback
214
def test_import_string_attribute_error(tmpdir, monkeypatch):
215
monkeypatch.syspath_prepend(str(tmpdir))
216
tmpdir.join("foo_test.py").write("from bar_test import value")
217
tmpdir.join("bar_test.py").write("raise AttributeError('bad')")
219
with pytest.raises(AttributeError) as info:
220
utils.import_string("foo_test")
222
assert "bad" in str(info.value)
224
with pytest.raises(AttributeError) as info:
225
utils.import_string("bar_test")
227
assert "bad" in str(info.value)
230
def test_find_modules():
231
assert list(utils.find_modules("werkzeug.debug")) == [
232
"werkzeug.debug.console",
233
"werkzeug.debug.repr",
234
"werkzeug.debug.tbtools",
238
def test_header_set_duplication_bug():
239
headers = Headers([("Content-Type", "text/html"), ("Foo", "bar"), ("Blub", "blah")])
240
headers["blub"] = "hehe"
241
headers["blafasel"] = "humm"
242
assert headers == Headers(
244
("Content-Type", "text/html"),
247
("blafasel", "humm"),
252
@pytest.mark.parametrize(
253
("path", "base_url", "absolute_location"),
255
("foo", "http://example.org/app", "http://example.org/app/foo/"),
256
("/foo", "http://example.org/app", "http://example.org/app/foo/"),
257
("/foo/bar", "http://example.org/", "http://example.org/foo/bar/"),
258
("/foo/bar", "http://example.org/app", "http://example.org/app/foo/bar/"),
259
("/foo?baz", "http://example.org/", "http://example.org/foo/?baz"),
260
("/foo/", "http://example.org/", "http://example.org/foo/"),
261
("/foo/", "http://example.org/app", "http://example.org/app/foo/"),
262
("/", "http://example.org/", "http://example.org/"),
263
("/", "http://example.org/app", "http://example.org/app/"),
266
@pytest.mark.parametrize("autocorrect", [False, True])
267
def test_append_slash_redirect(autocorrect, path, base_url, absolute_location):
270
rv = utils.append_slash_redirect(request.environ)
271
rv.autocorrect_location_header = autocorrect
275
response = client.get(path, base_url=base_url)
276
assert response.status_code == 308
279
assert response.headers["Location"].count("/") == 1
281
assert response.headers["Location"] == absolute_location
284
def test_cached_property_doc():
285
@utils.cached_property
290
assert foo.__doc__ == "testing"
291
assert foo.__name__ == "foo"
292
assert foo.__module__ == __name__
295
def test_secure_filename():
296
assert utils.secure_filename("My cool movie.mov") == "My_cool_movie.mov"
297
assert utils.secure_filename("../../../etc/passwd") == "etc_passwd"
299
utils.secure_filename("i contain cool \xfcml\xe4uts.txt")
300
== "i_contain_cool_umlauts.txt"
302
assert utils.secure_filename("__filename__") == "filename"
303
assert utils.secure_filename("foo$&^*)bar") == "foobar"