From e00c7c2cedcbcad3772e4522813c78bc9a860fbe Mon Sep 17 00:00:00 2001 From: Niklas Meinzer Date: Mon, 22 Apr 2019 21:06:22 +0200 Subject: [PATCH] Make LintMiddleware Python 3 compatible and add tests --- CHANGES.rst | 2 + src/werkzeug/middleware/lint.py | 10 +++- tests/middleware/test_lint.py | 87 +++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 tests/middleware/test_lint.py diff --git a/CHANGES.rst b/CHANGES.rst index 49c29ffbf..0df304c55 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,8 @@ Unreleased - Fix the filename format string in :class:`~middleware.profiler.ProfilerMiddleware` to correctly handle float values. (:issue:`1511`) +- Update :class:`~middleware.lint.LintMiddleware` to work on Python 3. + (:issue:`1510`) Version 0.15.2 diff --git a/src/werkzeug/middleware/lint.py b/src/werkzeug/middleware/lint.py index 15372819b..98f958177 100644 --- a/src/werkzeug/middleware/lint.py +++ b/src/werkzeug/middleware/lint.py @@ -14,6 +14,8 @@ """ from warnings import warn +from .._compat import implements_iterator +from .._compat import PY2 from .._compat import string_types from ..datastructures import Headers from ..http import is_entity_header @@ -124,10 +126,14 @@ def __call__(self, s): self._chunks.append(len(s)) +@implements_iterator class GuardedIterator(object): def __init__(self, iterator, headers_set, chunks): self._iterator = iterator - self._next = iter(iterator).next + if PY2: + self._next = iter(iterator).next + else: + self._next = iter(iterator).__next__ self.closed = False self.headers_set = headers_set self.chunks = chunks @@ -135,7 +141,7 @@ def __init__(self, iterator, headers_set, chunks): def __iter__(self): return self - def next(self): + def __next__(self): if self.closed: warn("Iterated over closed 'app_iter'.", WSGIWarning, stacklevel=2) diff --git a/tests/middleware/test_lint.py b/tests/middleware/test_lint.py new file mode 100644 index 000000000..748a53a38 --- /dev/null +++ b/tests/middleware/test_lint.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +import pytest + +from werkzeug.middleware.lint import HTTPWarning +from werkzeug.middleware.lint import LintMiddleware +from werkzeug.middleware.lint import WSGIWarning +from werkzeug.test import create_environ +from werkzeug.test import run_wsgi_app + + +def dummy_application(environ, start_response): + start_response("200 OK", [("Content-Type", "text/plain")]) + return ["Foo"] + + +def test_lint_middleware(): + """ Test lint middleware runs for a dummy applications without warnings """ + app = LintMiddleware(dummy_application) + + environ = create_environ("/test") + app_iter, status, headers = run_wsgi_app(app, environ, buffered=True) + assert status == "200 OK" + + +@pytest.mark.parametrize( + "key, value, message", + [ + ("wsgi.version", (0, 7), "Environ is not a WSGI 1.0 environ."), + ("SCRIPT_NAME", "test", "'SCRIPT_NAME' does not start with a slash:"), + ("PATH_INFO", "test", "'PATH_INFO' does not start with a slash:"), + ], +) +def test_lint_middleware_check_environ(key, value, message): + app = LintMiddleware(dummy_application) + + environ = create_environ("/test") + environ[key] = value + with pytest.warns(WSGIWarning, match=message): + app_iter, status, headers = run_wsgi_app(app, environ, buffered=True) + assert status == "200 OK" + + +def test_lint_middleware_invalid_status(): + def my_dummy_application(environ, start_response): + start_response("20 OK", [("Content-Type", "text/plain")]) + return ["Foo"] + + app = LintMiddleware(my_dummy_application) + + environ = create_environ("/test") + with pytest.warns(WSGIWarning) as record: + run_wsgi_app(app, environ, buffered=True) + + # Returning status 20 should raise three different warnings + assert len(record) == 3 + + +@pytest.mark.parametrize( + "headers, message", + [ + (tuple([("Content-Type", "text/plain")]), "header list is not a list"), + (["fo"], "Headers must tuple 2-item tuples"), + ([("status", "foo")], "The status header is not supported"), + ], +) +def test_lint_middleware_http_headers(headers, message): + def my_dummy_application(environ, start_response): + start_response("200 OK", headers) + return ["Foo"] + + app = LintMiddleware(my_dummy_application) + + environ = create_environ("/test") + with pytest.warns(WSGIWarning, match=message): + run_wsgi_app(app, environ, buffered=True) + + +def test_lint_middleware_invalid_location(): + def my_dummy_application(environ, start_response): + start_response("200 OK", [("location", "foo")]) + return ["Foo"] + + app = LintMiddleware(my_dummy_application) + + environ = create_environ("/test") + with pytest.warns(HTTPWarning, match="absolute URLs required for location header"): + run_wsgi_app(app, environ, buffered=True)