def extra_headers(self) -> None: sr = StubStartResponse() respond_with_html( sr, "<div>Täst</div>", extra_headers=[("X-Custom-Header", "Foobar")], ) sr.assert_header_equals("X-Custom-Header", "Foobar")
def error_if_content_type_also_in_extra_headers(self) -> None: sr = StubStartResponse() with assert_raises(ValueError): respond( sr, content_type="image/png", extra_headers=[("Content-Type", "image/jpeg")], )
def content_length(self) -> None: sr = StubStartResponse() respond_with_json(sr, {"foo": 33}) sr.assert_header_equals("Content-Length", "11")
class RouterTest(TestCase): @before def setup_router(self) -> None: self.router = Router() self.router.error_handling = False self.start_response = StubStartResponse() self.environment = default_environment() self.disable_logger() def disable_logger(self) -> None: logging.getLogger(LOGGER_NAME).disabled = True def _create_path_checker(self, expected_path: str) -> WSGIApplication: def handle(environ: WSGIEnvironment, sr: StartResponse) -> Sequence[bytes]: assert_equal(expected_path, environ["PATH_INFO"]) sr("200 OK", []) return [] return handle def handle_wsgi(self, method: str = "GET", path: str = "/") -> Iterable[bytes]: self.environment["REQUEST_METHOD"] = method self.environment["PATH_INFO"] = path return self.router(self.environment, self.start_response) @test def not_found_response_page(self) -> None: response = self.handle_wsgi("GET", "/foo/bar") html = b"".join(response).decode("utf-8") assert_equal( """<!DOCTYPE html> <html> <head> <title>404 — Not Found</title> </head> <body> <h1>404 — Not Found</h1> <p>Path '/foo/bar' not found.</p> </body> </html> """, html, ) @test def not_found_escape_path(self) -> None: response = self.handle_wsgi("GET", "/foo/<bar") html = b"".join(response).decode("utf-8") assert_in("<p>Path '/foo/<bar' not found.</p>", html) @test def no_routes(self) -> None: self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.NOT_FOUND) self.start_response.assert_header_equals("Content-Type", "text/html; charset=utf-8") @test def handler_request(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal("test.example.com", environ["SERVER_NAME"]) start_response("200 OK", []) return [b""] self.router.add_routes([("", "GET", handle)]) self.environment["SERVER_NAME"] = "test.example.com" self.handle_wsgi("GET", "") self.start_response.assert_status(HTTPStatus.OK) @test def empty_route(self) -> None: self.router.add_routes([("", "GET", handle_empty_path)]) self.handle_wsgi("GET", "") self.start_response.assert_status(HTTPStatus.OK) @test def root_route(self) -> None: self.router.add_routes([("", "GET", handle_empty_path)]) self.handle_wsgi("GET", "/") self.start_response.assert_status(HTTPStatus.OK) @test def first_level(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal("", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [] self.router.add_routes([("foo", "GET", handle)]) self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.OK) @test def first_level__trailing_slash(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal("/", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [] self.router.add_routes([("foo", "GET", handle)]) self.handle_wsgi("GET", "/foo/") self.start_response.assert_status(HTTPStatus.OK) @test def first_level_wrong_path(self) -> None: self.router.add_routes([("foo", "GET", handle_empty_path)]) self.handle_wsgi("GET", "/bar") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def level_mismatch_1(self) -> None: self.router.add_routes([("foo/bar", "GET", handle_empty_path)]) self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def level_mismatch_2(self) -> None: self.router.add_routes([("foo", "GET", handle_empty_path)]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def decode_path(self) -> None: self.router.add_routes([("foo/bär", "GET", handle_success)]) self.handle_wsgi("GET", "/foo/b%c3%a4r") self.start_response.assert_status(HTTPStatus.OK) @test def invalid_path_encoding(self) -> None: self.router.add_routes([("foo/bar", "GET", handle_success)]) self.handle_wsgi("GET", "/foo/b%c3r") self.start_response.assert_status(HTTPStatus.NOT_FOUND) # Method Handling @test def wrong_method_response_page(self) -> None: self.router.add_routes([("foo", "GET", fail_if_called), ("foo", "PUT", fail_if_called)]) response = self.handle_wsgi("POST", "/foo") html = b"".join(response).decode("utf-8") assert_equal( """<!DOCTYPE html> <html> <head> <title>405 — Method Not Allowed</title> </head> <body> <h1>405 — Method Not Allowed</h1> <p>Method 'POST' not allowed. Please try GET or PUT.</p> </body> </html> """, html, ) @test def wrong_method_escape_method(self) -> None: self.router.add_routes([("foo", "GET", fail_if_called)]) response = self.handle_wsgi("G<T", "/foo") html = b"".join(response).decode("utf-8") assert_in( "<p>Method 'G<T' not allowed. Please try GET.</p>", html, ) @test def wrong_method(self) -> None: self.router.add_routes([("foo", "GET", fail_if_called), ("foo", "PUT", fail_if_called)]) self.handle_wsgi("POST", "/foo") self.start_response.assert_status(HTTPStatus.METHOD_NOT_ALLOWED) self.start_response.assert_header_equals("Allow", "GET, PUT") @test def wrong_method__multiple_matches(self) -> None: self.router.add_routes([("foo", "GET", fail_if_called), ("foo", "GET", fail_if_called)]) self.handle_wsgi("POST", "/foo") self.start_response.assert_status(HTTPStatus.METHOD_NOT_ALLOWED) self.start_response.assert_header_equals("Allow", "GET") @test def call_right_method(self) -> None: self.router.add_routes([ ("foo", "GET", fail_if_called), ("foo", "POST", handle_success), ("foo", "PUT", fail_if_called), ]) self.handle_wsgi("POST", "/foo") self.start_response.assert_status(HTTPStatus.OK) # Path Templates @test def unknown_template(self) -> None: with assert_raises(KeyError): self.router.add_routes([("foo/{unknown}/bar", "GET", fail_if_called)]) @test def no_template(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal([], environ["rouver.path_args"]) start_response("200 OK", []) return [b""] self.router.add_routes([("foo/bar", "GET", handle)]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) @test def template(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal(["xyzxyz"], environ["rouver.path_args"]) start_response("200 OK", []) return [b""] def handle_path(request: Request, paths: Sequence[Any], path: str) -> str: assert_is_instance(request, Request) assert_equal((), paths) return path * 2 self.router.add_template_handler("handler", handle_path) self.router.add_routes([("foo/{handler}/bar", "GET", handle)]) self.handle_wsgi("GET", "/foo/xyz/bar") self.start_response.assert_status(HTTPStatus.OK) @test def multiple_templates(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal(["xyz", 123], environ["rouver.path_args"]) start_response("200 OK", []) return [b""] def handle_path(_: Request, paths: Sequence[Any], __: str) -> int: assert_equal(("xyz", ), paths) return 123 self.router.add_template_handler("handler1", lambda _, __, ___: "xyz") self.router.add_template_handler("handler2", handle_path) self.router.add_routes([("foo/{handler1}/bar/{handler2}", "GET", handle)]) self.handle_wsgi("GET", "/foo/xyz/bar/abc") self.start_response.assert_status(HTTPStatus.OK) @test def template_handler_is_passed_decoded_value(self) -> None: def handle_path(_: Request, __: Any, v: str) -> None: assert_equal("foo/bar", v) self.router.add_template_handler("handler", handle_path) self.router.add_routes([("foo/{handler}", "GET", handle_success)]) self.handle_wsgi("GET", "/foo/foo%2Fbar") self.start_response.assert_status(HTTPStatus.OK) @test def template_handler_is_not_passed_an_invalid_value(self) -> None: def handle_path(_: Request, __: Any, v: str) -> None: fail("template handler should not have been called") self.router.add_template_handler("handler", handle_path) self.router.add_routes([("foo/{handler}", "GET", handle_success)]) self.handle_wsgi("GET", "/foo/foo%C3bar") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def template_value_error(self) -> None: def raise_value_error(_: Request, __: Sequence[str], ___: str) -> None: raise ValueError() self.router.add_template_handler("handler", raise_value_error) self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)]) self.handle_wsgi("GET", "/foo/xyz/bar") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def template_multiple_matches(self) -> None: def raise_value_error(_: Request, __: Sequence[str], ___: str) -> None: raise ValueError() self.router.add_template_handler("handler1", raise_value_error) self.router.add_template_handler("handler2", lambda _, __, ___: None) self.router.add_routes([ ("foo/{handler1}/bar", "GET", fail_if_called), ("foo/{handler2}/bar", "GET", handle_success), ]) self.handle_wsgi("GET", "/foo/xyz/bar") self.start_response.assert_status(HTTPStatus.OK) @test def template_multiple_matches__match_first(self) -> None: self.router.add_template_handler("handler1", lambda _, __, ___: None) self.router.add_template_handler("handler2", lambda _, __, ___: None) self.router.add_routes([ ("foo/{handler1}/bar", "GET", handle_success), ("foo/{handler2}/bar", "GET", fail_if_called), ]) self.handle_wsgi("GET", "/foo/xyz/bar") self.start_response.assert_status(HTTPStatus.OK) @test def template_call_once_per_value(self) -> None: calls = 0 def increase_count(_: Request, __: Sequence[str], ___: str) -> None: nonlocal calls calls += 1 self.router.add_template_handler("handler", increase_count) self.router.add_routes([ ("foo/{handler}/bar", "GET", fail_if_called), ("foo/{handler}/baz", "GET", handle_success), ]) self.handle_wsgi("GET", "/foo/xyz/baz") assert_equal(1, calls) @test def template_call_twice_for_differing_values(self) -> None: calls = 0 def increase_count(_: Request, __: Sequence[str], ___: str) -> None: nonlocal calls calls += 1 self.router.add_template_handler("handler", increase_count) self.router.add_routes([ ("foo/{handler}/bar", "GET", fail_if_called), ("foo/xyz/{handler}", "GET", handle_success), ]) self.handle_wsgi("GET", "/foo/xyz/baz") assert_equal(2, calls) # Wildcard Paths @test def no_wildcard_path(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal("", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [b""] self.router.add_routes([("foo/bar", "GET", handle)]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard_path__no_trailing_slash(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal([], environ["rouver.path_args"]) assert_equal("", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [b""] self.router.add_routes([("foo/bar/*", "GET", handle)]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard_path__with_trailing_slash(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal([], environ["rouver.path_args"]) assert_equal("/", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [b""] self.router.add_routes([("foo/bar/*", "GET", handle)]) self.handle_wsgi("GET", "/foo/bar/") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard_path__additional_path(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal([], environ["rouver.path_args"]) assert_equal("/abc/def", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [b""] self.router.add_routes([("foo/bar/*", "GET", handle)]) self.handle_wsgi("GET", "/foo/bar/abc/def") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard_path__with_template(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal(["value"], environ["rouver.path_args"]) assert_equal("/abc/def", environ["rouver.wildcard_path"]) start_response("200 OK", []) return [b""] self.router.add_template_handler("bar", lambda *args: "value") self.router.add_routes([("foo/{bar}/*", "GET", handle)]) self.handle_wsgi("GET", "/foo/unknown/abc/def") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard_path__too_short(self) -> None: self.router.add_routes([("foo/bar/*", "GET", handle_success)]) self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def wildcard_path__does_not_match(self) -> None: self.router.add_routes([("foo/bar/*", "GET", handle_success)]) self.handle_wsgi("GET", "/foo/wrong") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def wildcard_path__not_at_end(self) -> None: with assert_raises(ValueError): self.router.add_routes([("foo/*/bar", "GET", handle_success)]) @test def wildcard__before_more_specific(self) -> None: self.router.add_routes([ ("foo/*", "GET", handle_success), ("foo/bar", "GET", fail_if_called), ]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) @test def wildcard__after_more_specific(self) -> None: self.router.add_routes([ ("foo/bar", "GET", handle_success), ("foo/*", "GET", fail_if_called), ]) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) # Sub routers @test def sub_router(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("sub", "GET", self._create_path_checker("/sub"))]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar/sub") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__no_match(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("sub", "GET", fail_if_called)]) self.router.add_sub_router("foo", sub) self.handle_wsgi("GET", "/wrong/sub") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def sub_router__base_with_slash(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("", "GET", self._create_path_checker("/"))]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar/") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__base_without_slash(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("", "GET", self._create_path_checker(""))]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__path_info(self) -> None: def app(env: WSGIEnvironment, sr: StartResponse) -> Iterable[bytes]: assert_equal("/foo", env["PATH_INFO"]) assert_equal("/sub/foo", env["rouver.original_path_info"]) sr("200 OK", []) return [] self.router.error_handling = False self.router.add_sub_router("sub", app) self.handle_wsgi("GET", "/sub/foo") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__path_info_encoding(self) -> None: expected_path = "/föo".encode("utf-8").decode("latin-1") def app(env: WSGIEnvironment, sr: StartResponse) -> Iterable[bytes]: assert_equal(expected_path, env["PATH_INFO"]) sr("200 OK", []) return [] self.router.error_handling = False self.router.add_sub_router("sub", app) self.handle_wsgi("GET", "/sub/föo".encode("utf-8").decode("latin-1")) self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__template_in_super_router(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal([], environ["rouver.path_args"]) start_response("200 OK", []) return [] def tmpl(_: Request, path: Sequence[str], v: str) -> str: assert_equal((), path) return v * 2 sub = Router() sub.error_handling = False sub.add_template_handler("tmpl", tmpl) sub.add_routes([("sub", "GET", handle)]) self.router.add_template_handler("tmpl", tmpl) self.router.add_sub_router("foo/{tmpl}", sub) self.handle_wsgi("GET", "/foo/bar/sub") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__template_in_sub_router(self) -> None: def handle(environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: assert_equal(["xyzxyz"], environ["rouver.path_args"]) start_response("200 OK", []) return [] def tmpl(_: Request, path: Sequence[str], v: str) -> str: assert_equal((), path) return v * 2 sub = Router() sub.error_handling = False sub.add_template_handler("tmpl", tmpl) sub.add_routes([("{tmpl}", "GET", handle)]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar/xyz") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__path_component(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("sub", "GET", handle_success)]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/barsub") self.start_response.assert_status(HTTPStatus.NOT_FOUND) @test def sub_router__match_after_other_routes(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("sub", "GET", fail_if_called)]) self.router.add_routes([("foo/bar/sub", "GET", handle_success)]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar/sub") self.start_response.assert_status(HTTPStatus.OK) @test def sub_router__accepts_any_wsgi_app(self) -> None: def sub(environ: WSGIEnvironment, sr: StartResponse) -> WSGIResponse: assert_equal("/sub", environ["PATH_INFO"]) sr("204 No Content", []) return [] self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/bar/sub") self.start_response.assert_status(HTTPStatus.NO_CONTENT) @test def sub_router__escaped_path(self) -> None: sub = Router() sub.error_handling = False sub.add_routes([("sub", "GET", self._create_path_checker("/s%75b"))]) self.router.add_sub_router("foo/bar", sub) self.handle_wsgi("GET", "/foo/b%61r/s%75b") self.start_response.assert_status(HTTPStatus.OK) # Error Handling @test def internal_error_page(self) -> None: def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise KeyError("Custom < error") self.router.error_handling = True self.router.add_routes([("foo", "GET", handle)]) response = self.handle_wsgi("GET", "/foo") html = b"".join(response).decode("utf-8") assert_equal( """<!DOCTYPE html> <html> <head> <title>500 — Internal Server Error</title> </head> <body> <h1>500 — Internal Server Error</h1> <p>Internal server error.</p> </body> </html> """, html, ) @test def template_key_error_with_error_handling(self) -> None: def raise_key_error(_: Request, __: Sequence[str], ___: str) -> None: raise KeyError() self.router.add_template_handler("handler", raise_key_error) self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)]) self.router.error_handling = True self.handle_wsgi("GET", "/foo/xyz/bar") self.start_response.assert_status(HTTPStatus.INTERNAL_SERVER_ERROR) @test def template_key_error_without_error_handling(self) -> None: def raise_key_error(_: Request, __: Sequence[str], ___: str) -> None: raise KeyError() self.router.add_template_handler("handler", raise_key_error) self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)]) self.router.error_handling = False with assert_raises(KeyError): self.handle_wsgi("GET", "/foo/xyz/bar") @test def handler_key_error_with_error_handling(self) -> None: def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise KeyError() self.router.error_handling = True self.router.add_routes([("foo", "GET", handle)]) self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.INTERNAL_SERVER_ERROR) @test def handler_key_error_without_error_handling(self) -> None: def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise KeyError() self.router.add_routes([("foo", "GET", handle)]) self.router.error_handling = False with assert_raises(KeyError): self.handle_wsgi("GET", "/foo") @test def http_error(self) -> None: def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise Unauthorized("Foo < Bar", www_authenticate=WWWAuthenticate("Test")) self.router.error_handling = False self.router.add_routes([("foo", "GET", handle)]) response = self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.UNAUTHORIZED) self.start_response.assert_header_equals("Content-Type", "text/html; charset=utf-8") self.start_response.assert_header_equals("WWW-Authenticate", "Test ") html = b"".join(response).decode("utf-8") assert_equal( """<!DOCTYPE html> <html> <head> <title>401 — Unauthorized</title> </head> <body> <h1>401 — Unauthorized</h1> <p>Foo < Bar</p> </body> </html> """, html, ) @test def arguments_error(self) -> None: def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise ArgumentsError({"foo": "bar"}) self.router.add_routes([("foo", "GET", handle)]) response = self.handle_wsgi("GET", "/foo") self.start_response.assert_status(HTTPStatus.BAD_REQUEST) html = b"".join(response).decode("utf-8") assert html.startswith("<!DOCTYPE html>") assert_regex( html, r'<li class="argument">\s*' r'<span class="argument-name">foo</span>:\s*' r'<span class="error-message">bar</span>\s*' r"</li>", )
def default_content_type(self) -> None: sr = StubStartResponse() respond_with_content(sr, b"") sr.assert_header_equals("Content-Type", "application/octet-stream")
def default_status(self) -> None: sr = StubStartResponse() respond_with_content(sr, b"") sr.assert_status(HTTPStatus.OK)
def content_type(self) -> None: sr = StubStartResponse() respond(sr, content_type="image/png") sr.assert_header_equals("Content-Type", "image/png")
class SeeOtherTest(TestCase): @before def setup_environment(self) -> None: self.environment = default_environment() self.start_response = StubStartResponse() @test def headers(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) see_other(request, self.start_response, "/foo/bar") self.start_response.assert_status(HTTPStatus.SEE_OTHER) self.start_response.assert_header_equals("Content-Type", "text/html; charset=utf-8") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def absolute_url(self) -> None: request = Request(self.environment) see_other(request, self.start_response, "http://example.com/foo") self.start_response.assert_header_equals("Location", "http://example.com/foo") @test def url_without_leading_slash(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" self.environment["PATH_INFO"] = "/abc/def/" request = Request(self.environment) see_other(request, self.start_response, "foo/bar") self.start_response.assert_header_equals( "Location", "http://www.example.com/abc/def/foo/bar") @test def url_path_without_trailing_slash(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" self.environment["PATH_INFO"] = "/abc/def" request = Request(self.environment) see_other(request, self.start_response, "foo/bar") self.start_response.assert_header_equals( "Location", "http://www.example.com/abc/foo/bar") @test def umlauts_in_url(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) see_other(request, self.start_response, "foo/bär") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/b%C3%A4r") @test def extra_headers(self) -> None: request = Request(self.environment) see_other( request, self.start_response, "foo", extra_headers=[("X-Foo", "Bar")], ) self.start_response.assert_header_equals("X-Foo", "Bar") @test def html(self) -> None: request = Request(self.environment) response = see_other(request, self.start_response, "foo/bar") html = b"".join(response).decode("utf-8") assert html.startswith("<!DOCTYPE html>") assert_in("http://www.example.com/foo/bar", html)
def content_length(self) -> None: sr = StubStartResponse() respond_with_html(sr, "<div>Test</div>") sr.assert_header_equals("Content-Length", "15")
def content_type(self) -> None: sr = StubStartResponse() respond_with_html(sr, "<div>Test</div>") sr.assert_header_equals("Content-Type", "text/html; charset=utf-8")
def custom_status(self) -> None: sr = StubStartResponse() respond_with_html(sr, "<div>Test</div>", status=HTTPStatus.NOT_ACCEPTABLE) sr.assert_status(HTTPStatus.NOT_ACCEPTABLE)
def default_status(self) -> None: sr = StubStartResponse() respond_with_html(sr, "<div>Test</div>") sr.assert_status(HTTPStatus.OK)
def json_as_object(self) -> None: sr = StubStartResponse() response = respond_with_json(sr, {"föo": 3}) assert_equal(b'{"f\\u00f6o": 3}', b"".join(response))
def json_as_str(self) -> None: sr = StubStartResponse() response = respond_with_json(sr, '{"föo": 3}') assert_equal('{"föo": 3}'.encode("utf-8"), b"".join(response))
def json_as_bytes(self) -> None: sr = StubStartResponse() response = respond_with_json(sr, b'{"foo": 3}') assert_equal(b'{"foo": 3}', b"".join(response))
class TemporaryRedirectTest(TestCase): @before def setup_environment(self) -> None: self.environment = default_environment() self.start_response = StubStartResponse() @test def headers(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) temporary_redirect(request, self.start_response, "/foo/bar") self.start_response.assert_status(HTTPStatus.TEMPORARY_REDIRECT) self.start_response.assert_header_equals("Content-Type", "text/html; charset=utf-8") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def absolute_url(self) -> None: request = Request(self.environment) temporary_redirect(request, self.start_response, "http://example.com/foo") self.start_response.assert_header_equals("Location", "http://example.com/foo") @test def url_without_leading_slash(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) temporary_redirect(request, self.start_response, "foo/bar") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def umlauts_in_url(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) temporary_redirect(request, self.start_response, "foo/bär") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/b%C3%A4r") @test def do_not_encode_cgi_arguments(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) temporary_redirect(request, self.start_response, "foo?bar=baz&abc=%6A;+,@:$") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo?bar=baz&abc=%6A;+,@:$") @test def extra_headers(self) -> None: request = Request(self.environment) temporary_redirect( request, self.start_response, "foo", extra_headers=[("X-Foo", "Bar")], ) self.start_response.assert_header_equals("X-Foo", "Bar") @test def html(self) -> None: request = Request(self.environment) response = temporary_redirect(request, self.start_response, "foo/bar") html = b"".join(response).decode("utf-8") assert html.startswith("<!DOCTYPE html>") assert_in("http://www.example.com/foo/bar", html)
def no_content_type(self) -> None: sr = StubStartResponse() respond(sr) sr.assert_header_missing("Content-Type")
def return_value(self) -> None: sr = StubStartResponse() response = respond_with_html(sr, "<div>Test</div>") assert_equal(b"<div>Test</div>", b"".join(response))
def setup_environment(self) -> None: self.environment = default_environment() self.start_response = StubStartResponse()
def return_value_encoding(self) -> None: sr = StubStartResponse() response = respond_with_html(sr, "<div>Täst</div>") assert_equal("<div>Täst</div>".encode("utf-8"), b"".join(response))
def content_type_in_extra_headers(self) -> None: sr = StubStartResponse() respond(sr, extra_headers=[("Content-Type", "image/png")]) sr.assert_header_equals("Content-Type", "image/png")
def default_status(self) -> None: sr = StubStartResponse() respond(sr) sr.assert_status(HTTPStatus.OK)
def response(self) -> None: sr = StubStartResponse() response = respond(sr) assert_equal(b"", b"".join(response))
class CreatedAtTest(TestCase): @before def setup_environment(self) -> None: self.environment = default_environment() self.start_response = StubStartResponse() @test def headers(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_at(request, self.start_response, "/foo/bar") self.start_response.assert_status(HTTPStatus.CREATED) self.start_response.assert_header_equals("Content-Type", "text/html; charset=utf-8") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def absolute_url(self) -> None: request = Request(self.environment) created_at(request, self.start_response, "http://example.com/foo") self.start_response.assert_header_equals("Location", "http://example.com/foo") @test def url_without_leading_slash(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_at(request, self.start_response, "foo/bar") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def umlauts_in_url(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_at(request, self.start_response, "foo/bär") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/b%C3%A4r") @test def extra_headers(self) -> None: request = Request(self.environment) created_at( request, self.start_response, "foo", extra_headers=[("X-Foo", "Bar")], ) self.start_response.assert_header_equals("X-Foo", "Bar") @test def html(self) -> None: request = Request(self.environment) response = created_at(request, self.start_response, "foo/bar") html = b"".join(response).decode("utf-8") assert html.startswith("<!DOCTYPE html>")
def custom_status(self) -> None: sr = StubStartResponse() respond_with_content(sr, b"", status=HTTPStatus.NOT_ACCEPTABLE) sr.assert_status(HTTPStatus.NOT_ACCEPTABLE)
class CreatedAsJSONTest(TestCase): @before def setup_environment(self) -> None: self.environment = default_environment() self.start_response = StubStartResponse() @test def headers(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_as_json(request, self.start_response, "/foo/bar", {}) self.start_response.assert_status(HTTPStatus.CREATED) self.start_response.assert_header_equals( "Content-Type", "application/json; charset=utf-8") self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def absolute_url(self) -> None: request = Request(self.environment) created_as_json(request, self.start_response, "http://example.com/foo", {}) self.start_response.assert_header_equals("Location", "http://example.com/foo") @test def url_without_leading_slash(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_as_json(request, self.start_response, "foo/bar", {}) self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/bar") @test def umlauts_in_url(self) -> None: self.environment["SERVER_NAME"] = "www.example.com" request = Request(self.environment) created_as_json(request, self.start_response, "foo/bär", {}) self.start_response.assert_header_equals( "Location", "http://www.example.com/foo/b%C3%A4r") @test def extra_headers(self) -> None: request = Request(self.environment) created_as_json( request, self.start_response, "foo", {}, extra_headers=[("X-Foo", "Bar")], ) self.start_response.assert_header_equals("X-Foo", "Bar") @test def json(self) -> None: request = Request(self.environment) response = created_as_json(request, self.start_response, "foo/bar", {"foo": 3}) json = json_decode(b"".join(response).decode("utf-8")) assert_equal({"foo": 3}, json)
def custom_content_type(self) -> None: sr = StubStartResponse() respond_with_content(sr, b"", content_type="text/plain") sr.assert_header_equals("Content-Type", "text/plain")
def extra_headers(self) -> None: sr = StubStartResponse() respond(sr, extra_headers=[("X-Custom-Header", "Foobar")]) sr.assert_header_equals("X-Custom-Header", "Foobar")
def setup_router(self) -> None: self.router = Router() self.router.error_handling = False self.start_response = StubStartResponse() self.environment = default_environment() self.disable_logger()
def content_type(self) -> None: sr = StubStartResponse() respond_with_json(sr, {}) sr.assert_header_equals("Content-Type", "application/json; charset=utf-8")