1import inspect 2from datetime import datetime 3 4import pytest 5 6from werkzeug import utils 7from werkzeug.datastructures import Headers 8from werkzeug.http import http_date 9from werkzeug.http import parse_date 10from werkzeug.test import Client 11from werkzeug.wrappers import Response 12 13 14def test_redirect(): 15 resp = utils.redirect("/füübär") 16 assert b"/f%C3%BC%C3%BCb%C3%A4r" in resp.get_data() 17 assert resp.headers["Location"] == "/f%C3%BC%C3%BCb%C3%A4r" 18 assert resp.status_code == 302 19 20 resp = utils.redirect("http://☃.net/", 307) 21 assert b"http://xn--n3h.net/" in resp.get_data() 22 assert resp.headers["Location"] == "http://xn--n3h.net/" 23 assert resp.status_code == 307 24 25 resp = utils.redirect("http://example.com/", 305) 26 assert resp.headers["Location"] == "http://example.com/" 27 assert resp.status_code == 305 28 29 30def test_redirect_xss(): 31 location = 'http://example.com/?xss="><script>alert(1)</script>' 32 resp = utils.redirect(location) 33 assert b"<script>alert(1)</script>" not in resp.get_data() 34 35 location = 'http://example.com/?xss="onmouseover="alert(1)' 36 resp = utils.redirect(location) 37 assert ( 38 b'href="http://example.com/?xss="onmouseover="alert(1)"' not in resp.get_data() 39 ) 40 41 42def test_redirect_with_custom_response_class(): 43 class MyResponse(Response): 44 pass 45 46 location = "http://example.com/redirect" 47 resp = utils.redirect(location, Response=MyResponse) 48 49 assert isinstance(resp, MyResponse) 50 assert resp.headers["Location"] == location 51 52 53def test_cached_property(): 54 foo = [] 55 56 class A: 57 def prop(self): 58 foo.append(42) 59 return 42 60 61 prop = utils.cached_property(prop) 62 63 a = A() 64 p = a.prop 65 q = a.prop 66 assert p == q == 42 67 assert foo == [42] 68 69 foo = [] 70 71 class A: 72 def _prop(self): 73 foo.append(42) 74 return 42 75 76 prop = utils.cached_property(_prop, name="prop") 77 del _prop 78 79 a = A() 80 p = a.prop 81 q = a.prop 82 assert p == q == 42 83 assert foo == [42] 84 85 86def test_can_set_cached_property(): 87 class A: 88 @utils.cached_property 89 def _prop(self): 90 return "cached_property return value" 91 92 a = A() 93 a._prop = "value" 94 assert a._prop == "value" 95 96 97def test_invalidate_cached_property(): 98 accessed = 0 99 100 class A: 101 @utils.cached_property 102 def prop(self): 103 nonlocal accessed 104 accessed += 1 105 return 42 106 107 a = A() 108 p = a.prop 109 q = a.prop 110 assert p == q == 42 111 assert accessed == 1 112 113 a.prop = 16 114 assert a.prop == 16 115 assert accessed == 1 116 117 del a.prop 118 r = a.prop 119 assert r == 42 120 assert accessed == 2 121 122 123def test_inspect_treats_cached_property_as_property(): 124 class A: 125 @utils.cached_property 126 def _prop(self): 127 return "cached_property return value" 128 129 attrs = inspect.classify_class_attrs(A) 130 for attr in attrs: 131 if attr.name == "_prop": 132 break 133 assert attr.kind == "property" 134 135 136def test_environ_property(): 137 class A: 138 environ = {"string": "abc", "number": "42"} 139 140 string = utils.environ_property("string") 141 missing = utils.environ_property("missing", "spam") 142 read_only = utils.environ_property("number") 143 number = utils.environ_property("number", load_func=int) 144 broken_number = utils.environ_property("broken_number", load_func=int) 145 date = utils.environ_property( 146 "date", None, parse_date, http_date, read_only=False 147 ) 148 foo = utils.environ_property("foo") 149 150 a = A() 151 assert a.string == "abc" 152 assert a.missing == "spam" 153 154 def test_assign(): 155 a.read_only = "something" 156 157 pytest.raises(AttributeError, test_assign) 158 assert a.number == 42 159 assert a.broken_number is None 160 assert a.date is None 161 a.date = datetime(2008, 1, 22, 10, 0, 0, 0) 162 assert a.environ["date"] == "Tue, 22 Jan 2008 10:00:00 GMT" 163 164 165def test_import_string(): 166 from datetime import date 167 from werkzeug.debug import DebuggedApplication 168 169 assert utils.import_string("datetime.date") is date 170 assert utils.import_string("datetime.date") is date 171 assert utils.import_string("datetime:date") is date 172 assert utils.import_string("XXXXXXXXXXXX", True) is None 173 assert utils.import_string("datetime.XXXXXXXXXXXX", True) is None 174 assert ( 175 utils.import_string("werkzeug.debug.DebuggedApplication") is DebuggedApplication 176 ) 177 pytest.raises(ImportError, utils.import_string, "XXXXXXXXXXXXXXXX") 178 pytest.raises(ImportError, utils.import_string, "datetime.XXXXXXXXXX") 179 180 181def test_import_string_provides_traceback(tmpdir, monkeypatch): 182 monkeypatch.syspath_prepend(str(tmpdir)) 183 # Couple of packages 184 dir_a = tmpdir.mkdir("a") 185 dir_b = tmpdir.mkdir("b") 186 # Totally packages, I promise 187 dir_a.join("__init__.py").write("") 188 dir_b.join("__init__.py").write("") 189 # 'aa.a' that depends on 'bb.b', which in turn has a broken import 190 dir_a.join("aa.py").write("from b import bb") 191 dir_b.join("bb.py").write("from os import a_typo") 192 193 # Do we get all the useful information in the traceback? 194 with pytest.raises(ImportError) as baz_exc: 195 utils.import_string("a.aa") 196 traceback = "".join(str(line) for line in baz_exc.traceback) 197 assert "bb.py':1" in traceback # a bit different than typical python tb 198 assert "from os import a_typo" in traceback 199 200 201def test_import_string_attribute_error(tmpdir, monkeypatch): 202 monkeypatch.syspath_prepend(str(tmpdir)) 203 tmpdir.join("foo_test.py").write("from bar_test import value") 204 tmpdir.join("bar_test.py").write("raise AttributeError('bad')") 205 206 with pytest.raises(AttributeError) as info: 207 utils.import_string("foo_test") 208 209 assert "bad" in str(info.value) 210 211 with pytest.raises(AttributeError) as info: 212 utils.import_string("bar_test") 213 214 assert "bad" in str(info.value) 215 216 217def test_find_modules(): 218 assert list(utils.find_modules("werkzeug.debug")) == [ 219 "werkzeug.debug.console", 220 "werkzeug.debug.repr", 221 "werkzeug.debug.tbtools", 222 ] 223 224 225def test_header_set_duplication_bug(): 226 headers = Headers([("Content-Type", "text/html"), ("Foo", "bar"), ("Blub", "blah")]) 227 headers["blub"] = "hehe" 228 headers["blafasel"] = "humm" 229 assert headers == Headers( 230 [ 231 ("Content-Type", "text/html"), 232 ("Foo", "bar"), 233 ("blub", "hehe"), 234 ("blafasel", "humm"), 235 ] 236 ) 237 238 239def test_append_slash_redirect(): 240 def app(env, sr): 241 return utils.append_slash_redirect(env)(env, sr) 242 243 client = Client(app) 244 response = client.get("foo", base_url="http://example.org/app") 245 assert response.status_code == 301 246 assert response.headers["Location"] == "http://example.org/app/foo/" 247 248 249def test_cached_property_doc(): 250 @utils.cached_property 251 def foo(): 252 """testing""" 253 return 42 254 255 assert foo.__doc__ == "testing" 256 assert foo.__name__ == "foo" 257 assert foo.__module__ == __name__ 258 259 260def test_secure_filename(): 261 assert utils.secure_filename("My cool movie.mov") == "My_cool_movie.mov" 262 assert utils.secure_filename("../../../etc/passwd") == "etc_passwd" 263 assert ( 264 utils.secure_filename("i contain cool \xfcml\xe4uts.txt") 265 == "i_contain_cool_umlauts.txt" 266 ) 267 assert utils.secure_filename("__filename__") == "filename" 268 assert utils.secure_filename("foo$&^*)bar") == "foobar" 269