# -*- coding: utf-8 -*- """ tests.utils ~~~~~~~~~~~ General utilities. :copyright: 2007 Pallets :license: BSD-3-Clause """ import inspect from datetime import datetime import pytest from werkzeug import utils from werkzeug._compat import text_type from werkzeug.datastructures import Headers from werkzeug.http import http_date from werkzeug.http import parse_date from werkzeug.test import Client from werkzeug.wrappers import BaseResponse def test_redirect(): resp = utils.redirect(u"/füübär") assert b"/f%C3%BC%C3%BCb%C3%A4r" in resp.get_data() assert resp.headers["Location"] == "/f%C3%BC%C3%BCb%C3%A4r" assert resp.status_code == 302 resp = utils.redirect(u"http://☃.net/", 307) assert b"http://xn--n3h.net/" in resp.get_data() assert resp.headers["Location"] == "http://xn--n3h.net/" assert resp.status_code == 307 resp = utils.redirect("http://example.com/", 305) assert resp.headers["Location"] == "http://example.com/" assert resp.status_code == 305 def test_redirect_xss(): location = 'http://example.com/?xss=">' resp = utils.redirect(location) assert b"" not in resp.get_data() location = 'http://example.com/?xss="onmouseover="alert(1)' resp = utils.redirect(location) assert ( b'href="http://example.com/?xss="onmouseover="alert(1)"' not in resp.get_data() ) def test_redirect_with_custom_response_class(): class MyResponse(BaseResponse): pass location = "http://example.com/redirect" resp = utils.redirect(location, Response=MyResponse) assert isinstance(resp, MyResponse) assert resp.headers["Location"] == location def test_cached_property(): foo = [] class A(object): def prop(self): foo.append(42) return 42 prop = utils.cached_property(prop) a = A() p = a.prop q = a.prop assert p == q == 42 assert foo == [42] foo = [] class A(object): def _prop(self): foo.append(42) return 42 prop = utils.cached_property(_prop, name="prop") del _prop a = A() p = a.prop q = a.prop assert p == q == 42 assert foo == [42] def test_can_set_cached_property(): class A(object): @utils.cached_property def _prop(self): return "cached_property return value" a = A() a._prop = "value" assert a._prop == "value" def test_can_invalidate_cached_property(): foo = [] class A(object): def prop(self): foo.append(42) return 42 prop = utils.cached_property(prop) a = A() p = a.prop q = a.prop assert p == q == 42 assert foo == [42] utils.invalidate_cached_property(a, "prop") r = a.prop assert r == 42 assert foo == [42, 42] s = a.prop assert s == 42 assert foo == [42, 42] def test_invalidate_cached_property_on_non_property(): class A(object): def __init__(self): self.prop = 42 a = A() with pytest.raises(TypeError): utils.invalidate_cached_property(a, "prop") def test_inspect_treats_cached_property_as_property(): class A(object): @utils.cached_property def _prop(self): return "cached_property return value" attrs = inspect.classify_class_attrs(A) for attr in attrs: if attr.name == "_prop": break assert attr.kind == "property" def test_environ_property(): class A(object): environ = {"string": "abc", "number": "42"} string = utils.environ_property("string") missing = utils.environ_property("missing", "spam") read_only = utils.environ_property("number") number = utils.environ_property("number", load_func=int) broken_number = utils.environ_property("broken_number", load_func=int) date = utils.environ_property( "date", None, parse_date, http_date, read_only=False ) foo = utils.environ_property("foo") a = A() assert a.string == "abc" assert a.missing == "spam" def test_assign(): a.read_only = "something" pytest.raises(AttributeError, test_assign) assert a.number == 42 assert a.broken_number is None assert a.date is None a.date = datetime(2008, 1, 22, 10, 0, 0, 0) assert a.environ["date"] == "Tue, 22 Jan 2008 10:00:00 GMT" def test_escape(): class Foo(str): def __html__(self): return text_type(self) assert utils.escape(None) == "" assert utils.escape(42) == "42" assert utils.escape("<>") == "<>" assert utils.escape('"foo"') == ""foo"" assert utils.escape(Foo("")) == "" def test_unescape(): assert utils.unescape("<ä>") == u"<ä>" def test_import_string(): from datetime import date from werkzeug.debug import DebuggedApplication assert utils.import_string("datetime.date") is date assert utils.import_string(u"datetime.date") is date assert utils.import_string("datetime:date") is date assert utils.import_string("XXXXXXXXXXXX", True) is None assert utils.import_string("datetime.XXXXXXXXXXXX", True) is None assert ( utils.import_string(u"werkzeug.debug.DebuggedApplication") is DebuggedApplication ) pytest.raises(ImportError, utils.import_string, "XXXXXXXXXXXXXXXX") pytest.raises(ImportError, utils.import_string, "datetime.XXXXXXXXXX") def test_import_string_provides_traceback(tmpdir, monkeypatch): monkeypatch.syspath_prepend(str(tmpdir)) # Couple of packages dir_a = tmpdir.mkdir("a") dir_b = tmpdir.mkdir("b") # Totally packages, I promise dir_a.join("__init__.py").write("") dir_b.join("__init__.py").write("") # 'aa.a' that depends on 'bb.b', which in turn has a broken import dir_a.join("aa.py").write("from b import bb") dir_b.join("bb.py").write("from os import a_typo") # Do we get all the useful information in the traceback? with pytest.raises(ImportError) as baz_exc: utils.import_string("a.aa") traceback = "".join((str(line) for line in baz_exc.traceback)) assert "bb.py':1" in traceback # a bit different than typical python tb assert "from os import a_typo" in traceback def test_import_string_attribute_error(tmpdir, monkeypatch): monkeypatch.syspath_prepend(str(tmpdir)) tmpdir.join("foo_test.py").write("from bar_test import value") tmpdir.join("bar_test.py").write("raise AttributeError('bad')") with pytest.raises(AttributeError) as info: utils.import_string("foo_test") assert "bad" in str(info.value) with pytest.raises(AttributeError) as info: utils.import_string("bar_test") assert "bad" in str(info.value) def test_find_modules(): assert list(utils.find_modules("werkzeug.debug")) == [ "werkzeug.debug.console", "werkzeug.debug.repr", "werkzeug.debug.tbtools", ] def test_html_builder(): html = utils.html xhtml = utils.xhtml assert html.p("Hello World") == "

Hello World

" assert html.a("Test", href="#") == 'Test' assert html.br() == "
" assert xhtml.br() == "
" assert html.img(src="foo") == '' assert xhtml.img(src="foo") == '' assert html.html( html.head(html.title("foo"), html.script(type="text/javascript")) ) == ( 'foo" ) assert html("") == "<foo>" assert html.input(disabled=True) == "" assert xhtml.input(disabled=True) == '' assert html.input(disabled="") == "" assert xhtml.input(disabled="") == "" assert html.input(disabled=None) == "" assert xhtml.input(disabled=None) == "" assert ( html.script('alert("Hello World");') == '' ) assert ( xhtml.script('alert("Hello World");') == '' ) def test_validate_arguments(): def take_none(): pass def take_two(a, b): pass def take_two_one_default(a, b=0): pass assert utils.validate_arguments(take_two, (1, 2), {}) == ((1, 2), {}) assert utils.validate_arguments(take_two, (1,), {"b": 2}) == ((1, 2), {}) assert utils.validate_arguments(take_two_one_default, (1,), {}) == ((1, 0), {}) assert utils.validate_arguments(take_two_one_default, (1, 2), {}) == ((1, 2), {}) pytest.raises( utils.ArgumentValidationError, utils.validate_arguments, take_two, (), {} ) assert utils.validate_arguments(take_none, (1, 2), {"c": 3}) == ((), {}) pytest.raises( utils.ArgumentValidationError, utils.validate_arguments, take_none, (1,), {}, drop_extra=False, ) pytest.raises( utils.ArgumentValidationError, utils.validate_arguments, take_none, (), {"a": 1}, drop_extra=False, ) def test_header_set_duplication_bug(): headers = Headers([("Content-Type", "text/html"), ("Foo", "bar"), ("Blub", "blah")]) headers["blub"] = "hehe" headers["blafasel"] = "humm" assert headers == Headers( [ ("Content-Type", "text/html"), ("Foo", "bar"), ("blub", "hehe"), ("blafasel", "humm"), ] ) def test_append_slash_redirect(): def app(env, sr): return utils.append_slash_redirect(env)(env, sr) client = Client(app, BaseResponse) response = client.get("foo", base_url="http://example.org/app") assert response.status_code == 301 assert response.headers["Location"] == "http://example.org/app/foo/" def test_cached_property_doc(): @utils.cached_property def foo(): """testing""" return 42 assert foo.__doc__ == "testing" assert foo.__name__ == "foo" assert foo.__module__ == __name__ def test_secure_filename(): assert utils.secure_filename("My cool movie.mov") == "My_cool_movie.mov" assert utils.secure_filename("../../../etc/passwd") == "etc_passwd" assert ( utils.secure_filename(u"i contain cool \xfcml\xe4uts.txt") == "i_contain_cool_umlauts.txt" ) assert utils.secure_filename("__filename__") == "filename" assert utils.secure_filename("foo$&^*)bar") == "foobar"