Skip to content

test_routes_server_response

Tests for routes server response framing behavior.

Classes

RoutesServerWriteResponseTests

Bases: TestCase

Functions

test_sets_content_length_for_large_json_payload()
Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_sets_content_length_for_large_json_payload(self):
    data = "x" * 4096
    parsed = _FakeResponseObject(
        status=base.OK,
        data=data,
        headers={"Content-Type": "application/json"},
    )

    result = self._run_write_response(parsed)

    self.assertEqual([base.OK], result.statuses)
    self.assertEqual(1, result.end_headers_calls)
    self.assertEqual(data.encode("utf-8"), result.wfile.writes[0])
    self.assertIn(
        ("Content-Length", str(len(data.encode("utf-8")))), result.headers
    )
test_encodes_string_body_as_utf8_bytes()
Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_encodes_string_body_as_utf8_bytes(self):
    data = u"caf\u00e9"
    parsed = _FakeResponseObject(
        status=base.OK,
        data=data,
        headers={"Content-Type": "application/json"},
    )

    result = self._run_write_response(parsed)
    expected = data.encode("utf-8")

    self.assertEqual(expected, result.wfile.writes[0])
    self.assertIn(("Content-Length", str(len(expected))), result.headers)
test_writes_newline_when_body_is_none()
Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_writes_newline_when_body_is_none(self):
    parsed = _FakeResponseObject(status=base.NO_CONTENT, data=None, headers={})

    result = self._run_write_response(parsed)

    self.assertEqual([base.NO_CONTENT], result.statuses)
    self.assertEqual([b"\n"], result.wfile.writes)
    self.assertIn(("Content-Length", "1"), result.headers)
    self.assertEqual(1, result.end_headers_calls)
test_calls_end_headers_without_custom_headers()
Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_calls_end_headers_without_custom_headers(self):
    parsed = _FakeResponseObject(status=base.OK, data="ok", headers={})

    result = self._run_write_response(parsed)

    self.assertEqual(1, result.end_headers_calls)
    self.assertEqual([b"ok"], result.wfile.writes)
test_overrides_existing_content_length_header()
Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_overrides_existing_content_length_header(self):
    data = "abc123"
    parsed = _FakeResponseObject(
        status=base.OK,
        data=data,
        headers={
            "Content-Type": "application/json",
            "Content-Length": "99999",
        },
    )

    result = self._run_write_response(parsed)

    content_length_headers = [
        pair for pair in result.headers if pair[0].lower() == "content-length"
    ]
    self.assertEqual(1, len(content_length_headers))
    self.assertEqual(str(len(data.encode("utf-8"))), content_length_headers[0][1])

RoutesServerQueryParsingTests

Bases: TestCase

Tests for the query-string parsing logic in _prepare_request.

Functions

test_single_value_key_flattened_to_string()

A query param with one value should be stored as a plain string.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_single_value_key_flattened_to_string(self):
    """A query param with one value should be stored as a plain string."""
    request = self._prepare("/items/", "/items/", "a=1")
    self.assertEqual("1", request.query_params["a"])
test_multiple_distinct_keys_parsed_independently()

Each distinct key in the query string is stored as its own entry.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_multiple_distinct_keys_parsed_independently(self):
    """Each distinct key in the query string is stored as its own entry."""
    request = self._prepare("/items/", "/items/", "a=1&b=2")
    self.assertEqual("1", request.query_params["a"])
    self.assertEqual("2", request.query_params["b"])
test_empty_query_string_produces_empty_dict()

An absent query string leaves query_params empty.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_empty_query_string_produces_empty_dict(self):
    """An absent query string leaves query_params empty."""
    request = self._prepare("/items/", "/items/", "")
    self.assertEqual({}, request.query_params)
test_none_query_string_produces_empty_dict()

A None query string leaves query_params empty.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_none_query_string_produces_empty_dict(self):
    """A None query string leaves query_params empty."""
    request = self._prepare("/items/", "/items/", None)
    self.assertEqual({}, request.query_params)
test_repeated_key_stored_as_list()

A key that appears more than once should be stored as a list.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_repeated_key_stored_as_list(self):
    """A key that appears more than once should be stored as a list."""
    request = self._prepare("/items/", "/items/", "tag=a&tag=b")
    self.assertIsInstance(request.query_params["tag"], list)
    self.assertIn("a", request.query_params["tag"])
    self.assertIn("b", request.query_params["tag"])
test_repeated_key_list_preserves_all_values()

All values for a repeated key must be present — none are dropped.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_repeated_key_list_preserves_all_values(self):
    """All values for a repeated key must be present — none are dropped."""
    request = self._prepare("/items/", "/items/", "tag=x&tag=y&tag=z")
    self.assertEqual(3, len(request.query_params["tag"]))
test_mixed_single_and_multi_value_keys()

Single-value and multi-value keys can coexist in the same query.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_mixed_single_and_multi_value_keys(self):
    """Single-value and multi-value keys can coexist in the same query."""
    request = self._prepare("/search/", "/search/", "q=hello&tag=a&tag=b")
    self.assertEqual("hello", request.query_params["q"])
    self.assertIsInstance(request.query_params["tag"], list)
    self.assertEqual(2, len(request.query_params["tag"]))
test_url_encoded_value_is_decoded()

URL percent-encoding in query values must be decoded.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_url_encoded_value_is_decoded(self):
    """URL percent-encoding in query values must be decoded."""
    request = self._prepare("/items/", "/items/", "name=hello+world")
    # parse_qs decodes '+' as a space by default
    self.assertIn("hello", request.query_params["name"])
test_url_encoded_special_characters()

Percent-encoded characters in query values are decoded properly.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_url_encoded_special_characters(self):
    """Percent-encoded characters in query values are decoded properly."""
    request = self._prepare("/items/", "/items/", "q=caf%C3%A9")
    self.assertIn(u"caf\u00e9", request.query_params["q"])
test_query_params_do_not_affect_request_path()

Query string parameters must not bleed into the request path.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_query_params_do_not_affect_request_path(self):
    """Query string parameters must not bleed into the request path."""
    request = self._prepare("/items/", "/items/", "a=1&b=2")
    self.assertEqual("/items/", request.path)
test_query_params_do_not_affect_route_params()

Query parameters are stored separately from URL path parameters.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_query_params_do_not_affect_route_params(self):
    """Query parameters are stored separately from URL path parameters."""
    request = self._prepare("/items/<id>", "/items/42", "filter=active")
    # route params captured from path placeholders
    param_keys = [p.key for p in request.params]
    self.assertNotIn("filter", param_keys)
    # query params available via query_params
    self.assertEqual("active", request.query_params["filter"])

RoutesServerHandlerKwargsTests

Bases: TestCase

Tests that query_params are injected into handler kwargs correctly.

Functions

test_single_query_param_injected_as_kwarg()

A single-value query param is passed to the handler as a kwarg.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_single_query_param_injected_as_kwarg(self):
    """A single-value query param is passed to the handler as a kwarg."""
    captured = {}

    def my_handler(request, limit):
        captured["limit"] = limit

    request = self._make_request(query_params={"limit": "10"})
    kwargs = handler.RequestHandler.prepare_handler_kwargs(
        request=request, handler=my_handler
    )
    self.assertIn("limit", kwargs)
    self.assertEqual("10", kwargs["limit"])
test_multi_value_query_param_injected_as_list()

A repeated query param is passed to the handler as a list kwarg.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_multi_value_query_param_injected_as_list(self):
    """A repeated query param is passed to the handler as a list kwarg."""
    captured = {}

    def my_handler(request, tag):
        captured["tag"] = tag

    request = self._make_request(query_params={"tag": ["a", "b"]})
    kwargs = handler.RequestHandler.prepare_handler_kwargs(
        request=request, handler=my_handler
    )
    self.assertIn("tag", kwargs)
    self.assertIsInstance(kwargs["tag"], list)
    self.assertEqual(["a", "b"], kwargs["tag"])
test_query_param_not_in_handler_signature_is_excluded()

Query params that don't match handler parameters are filtered out.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_query_param_not_in_handler_signature_is_excluded(self):
    """Query params that don't match handler parameters are filtered out."""

    def my_handler(request):
        pass

    request = self._make_request(query_params={"unknown_param": "value"})
    kwargs = handler.RequestHandler.prepare_handler_kwargs(
        request=request, handler=my_handler
    )
    self.assertNotIn("unknown_param", kwargs)
test_request_object_always_injected()

The request object is always present in handler kwargs.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_request_object_always_injected(self):
    """The request object is always present in handler kwargs."""

    def my_handler(request):
        pass

    request = self._make_request(query_params={"a": "1"})
    kwargs = handler.RequestHandler.prepare_handler_kwargs(
        request=request, handler=my_handler
    )
    self.assertIn("request", kwargs)
    self.assertIs(request, kwargs["request"])
test_query_params_and_route_params_coexist_in_kwargs()

Route path params and query params are both present in kwargs.

Source code in pyrevitlib/pyrevit/unittests/test_routes_server_response.py
def test_query_params_and_route_params_coexist_in_kwargs(self):
    """Route path params and query params are both present in kwargs."""
    from pyrevit.routes.server.router import RouteParam

    route_params = [RouteParam(key="item_id", value="99")]

    def my_handler(request, item_id, sort):
        pass

    request = self._make_request(
        query_params={"sort": "asc"}, params=route_params
    )
    kwargs = handler.RequestHandler.prepare_handler_kwargs(
        request=request, handler=my_handler
    )
    self.assertEqual("99", kwargs["item_id"])
    self.assertEqual("asc", kwargs["sort"])