From: Tom Christie Date: Tue, 5 Dec 2023 13:24:34 +0000 (+0000) Subject: Reorganise tests in 'test_url.py' (#2981) X-Git-Tag: 0.26.0~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=724eced022299c1beacce399f41dd9091e16a65a;p=thirdparty%2Fhttpx.git Reorganise tests in 'test_url.py' (#2981) * Reorganise tests in 'test_url.py' * Linting --- diff --git a/tests/models/test_url.py b/tests/models/test_url.py index a47205f9..7e8307d3 100644 --- a/tests/models/test_url.py +++ b/tests/models/test_url.py @@ -3,76 +3,6 @@ import pytest import httpx -@pytest.mark.parametrize( - "given,idna,host,raw_host,scheme,port", - [ - ( - "http://中国.icom.museum:80/", - "http://xn--fiqs8s.icom.museum:80/", - "中国.icom.museum", - b"xn--fiqs8s.icom.museum", - "http", - None, - ), - ( - "http://Königsgäßchen.de", - "http://xn--knigsgchen-b4a3dun.de", - "königsgäßchen.de", - b"xn--knigsgchen-b4a3dun.de", - "http", - None, - ), - ( - "https://faß.de", - "https://xn--fa-hia.de", - "faß.de", - b"xn--fa-hia.de", - "https", - None, - ), - ( - "https://βόλος.com:443", - "https://xn--nxasmm1c.com:443", - "βόλος.com", - b"xn--nxasmm1c.com", - "https", - None, - ), - ( - "http://ශ්‍රී.com:444", - "http://xn--10cl1a0b660p.com:444", - "ශ්‍රී.com", - b"xn--10cl1a0b660p.com", - "http", - 444, - ), - ( - "https://نامه‌ای.com:4433", - "https://xn--mgba3gch31f060k.com:4433", - "نامه‌ای.com", - b"xn--mgba3gch31f060k.com", - "https", - 4433, - ), - ], - ids=[ - "http_with_port", - "unicode_tr46_compat", - "https_without_port", - "https_with_port", - "http_with_custom_port", - "https_with_custom_port", - ], -) -def test_idna_url(given, idna, host, raw_host, scheme, port): - url = httpx.URL(given) - assert url == httpx.URL(idna) - assert url.host == host - assert url.raw_host == raw_host - assert url.scheme == scheme - assert url.port == port - - def test_url(): url = httpx.URL("https://example.org:123/path/to/somewhere?abc=123#anchor") assert url.scheme == "https" @@ -91,12 +21,102 @@ def test_url(): assert new.scheme == "http" +def test_url_with_empty_query(): + """ + URLs with and without a trailing `?` but an empty query component + should preserve the information on the raw path. + """ + url = httpx.URL("https://www.example.com/path") + assert url.path == "/path" + assert url.query == b"" + assert url.raw_path == b"/path" + + url = httpx.URL("https://www.example.com/path?") + assert url.path == "/path" + assert url.query == b"" + assert url.raw_path == b"/path?" + + +def test_url_query_encoding(): + """ + URL query parameters should use '%20' to encoding spaces, + and should treat '/' as a safe character. This behaviour differs + across clients, but we're matching browser behaviour here. + + See https://github.com/encode/httpx/issues/2536 + and https://github.com/encode/httpx/discussions/2460 + """ + url = httpx.URL("https://www.example.com/?a=b c&d=e/f") + assert url.raw_path == b"/?a=b%20c&d=e%2Ff" + + url = httpx.URL("https://www.example.com/", params={"a": "b c", "d": "e/f"}) + assert url.raw_path == b"/?a=b%20c&d=e%2Ff" + + +def test_url_with_url_encoded_path(): + url = httpx.URL("https://www.example.com/path%20to%20somewhere") + assert url.path == "/path to somewhere" + assert url.query == b"" + assert url.raw_path == b"/path%20to%20somewhere" + + +def test_url_raw_compatibility(): + url = httpx.URL("https://www.example.com/path") + scheme, host, port, raw_path = url.raw + + assert scheme == b"https" + assert host == b"www.example.com" + assert port is None + assert raw_path == b"/path" + + +def test_url_invalid(): + """ + Ensure that invalid URLs raise an `httpx.InvalidURL` exception. + """ + with pytest.raises(httpx.InvalidURL): + httpx.URL("https://😇/") + + def test_url_eq_str(): + """ + Ensure that `httpx.URL` supports the equality operator, + and can be compared against plain strings. + """ url = httpx.URL("https://example.org:123/path/to/somewhere?abc=123#anchor") assert url == "https://example.org:123/path/to/somewhere?abc=123#anchor" assert str(url) == url +def test_url_set(): + """ + Ensure that `httpx.URL` instances can be used in sets. + """ + urls = ( + httpx.URL("http://example.org:123/path/to/somewhere"), + httpx.URL("http://example.org:123/path/to/somewhere/else"), + ) + + url_set = set(urls) + + assert all(url in urls for url in url_set) + + +def test_url_invalid_type(): + """ + Ensure that invalid types on `httpx.URL()` raise a `TypeError`. + """ + + class ExternalURLClass: # representing external URL class + pass + + with pytest.raises(TypeError): + httpx.URL(ExternalURLClass()) # type: ignore + + +# Tests for `QueryParams`. + + def test_url_params(): url = httpx.URL("https://example.org:123/path/to/somewhere", params={"a": "123"}) assert str(url) == "https://example.org:123/path/to/somewhere?a=123" @@ -109,6 +129,9 @@ def test_url_params(): assert url.params == httpx.QueryParams({"a": "123"}) +# Tests for `URL.join()`. + + def test_url_join(): """ Some basic URL joining tests. @@ -124,38 +147,6 @@ def test_url_join(): assert url.join("../../somewhere-else") == "https://example.org:123/somewhere-else" -def test_url_set_param_manipulation(): - """ - Some basic URL query parameter manipulation. - """ - url = httpx.URL("https://example.org:123/?a=123") - assert url.copy_set_param("a", "456") == "https://example.org:123/?a=456" - - -def test_url_add_param_manipulation(): - """ - Some basic URL query parameter manipulation. - """ - url = httpx.URL("https://example.org:123/?a=123") - assert url.copy_add_param("a", "456") == "https://example.org:123/?a=123&a=456" - - -def test_url_remove_param_manipulation(): - """ - Some basic URL query parameter manipulation. - """ - url = httpx.URL("https://example.org:123/?a=123") - assert url.copy_remove_param("a") == "https://example.org:123/" - - -def test_url_merge_params_manipulation(): - """ - Some basic URL query parameter manipulation. - """ - url = httpx.URL("https://example.org:123/?a=123") - assert url.copy_merge_params({"b": "456"}) == "https://example.org:123/?a=123&b=456" - - def test_relative_url_join(): url = httpx.URL("/path/to/somewhere") assert url.join("/somewhere-else") == "/somewhere-else" @@ -219,15 +210,15 @@ def test_url_join_rfc3986(): assert url.join("g#s/../x") == "http://example.com/b/c/g#s/../x" -def test_url_set(): - urls = ( - httpx.URL("http://example.org:123/path/to/somewhere"), - httpx.URL("http://example.org:123/path/to/somewhere/else"), - ) +def test_resolution_error_1833(): + """ + See https://github.com/encode/httpx/issues/1833 + """ + url = httpx.URL("https://example.com/?[]") + assert url.join("/") == "https://example.com/" - url_set = set(urls) - assert all(url in urls for url in url_set) +# Tests for `URL.copy_with()`. def test_url_copywith_authority_subcomponents(): @@ -321,56 +312,120 @@ def test_url_copywith_security(): url.copy_with(scheme=bad) -def test_url_invalid(): - with pytest.raises(httpx.InvalidURL): - httpx.URL("https://😇/") +# Tests for copy-modifying-parameters methods. +# +# `URL.copy_set_param()` +# `URL.copy_add_param()` +# `URL.copy_remove_param()` +# `URL.copy_merge_params()` -def test_url_invalid_type(): - class ExternalURLClass: # representing external URL class - pass - - with pytest.raises(TypeError): - httpx.URL(ExternalURLClass()) # type: ignore +def test_url_set_param_manipulation(): + """ + Some basic URL query parameter manipulation. + """ + url = httpx.URL("https://example.org:123/?a=123") + assert url.copy_set_param("a", "456") == "https://example.org:123/?a=456" -def test_url_with_empty_query(): +def test_url_add_param_manipulation(): """ - URLs with and without a trailing `?` but an empty query component - should preserve the information on the raw path. + Some basic URL query parameter manipulation. """ - url = httpx.URL("https://www.example.com/path") - assert url.path == "/path" - assert url.query == b"" - assert url.raw_path == b"/path" - - url = httpx.URL("https://www.example.com/path?") - assert url.path == "/path" - assert url.query == b"" - assert url.raw_path == b"/path?" + url = httpx.URL("https://example.org:123/?a=123") + assert url.copy_add_param("a", "456") == "https://example.org:123/?a=123&a=456" -def test_url_query_encoding(): +def test_url_remove_param_manipulation(): """ - URL query parameters should use '%20' to encoding spaces, - and should treat '/' as a safe character. This behaviour differs - across clients, but we're matching browser behaviour here. + Some basic URL query parameter manipulation. + """ + url = httpx.URL("https://example.org:123/?a=123") + assert url.copy_remove_param("a") == "https://example.org:123/" - See https://github.com/encode/httpx/issues/2536 - and https://github.com/encode/httpx/discussions/2460 + +def test_url_merge_params_manipulation(): """ - url = httpx.URL("https://www.example.com/?a=b c&d=e/f") - assert url.raw_path == b"/?a=b%20c&d=e%2Ff" + Some basic URL query parameter manipulation. + """ + url = httpx.URL("https://example.org:123/?a=123") + assert url.copy_merge_params({"b": "456"}) == "https://example.org:123/?a=123&b=456" - url = httpx.URL("https://www.example.com/", params={"a": "b c", "d": "e/f"}) - assert url.raw_path == b"/?a=b%20c&d=e%2Ff" +# Tests for IDNA hostname support. -def test_url_with_url_encoded_path(): - url = httpx.URL("https://www.example.com/path%20to%20somewhere") - assert url.path == "/path to somewhere" - assert url.query == b"" - assert url.raw_path == b"/path%20to%20somewhere" + +@pytest.mark.parametrize( + "given,idna,host,raw_host,scheme,port", + [ + ( + "http://中国.icom.museum:80/", + "http://xn--fiqs8s.icom.museum:80/", + "中国.icom.museum", + b"xn--fiqs8s.icom.museum", + "http", + None, + ), + ( + "http://Königsgäßchen.de", + "http://xn--knigsgchen-b4a3dun.de", + "königsgäßchen.de", + b"xn--knigsgchen-b4a3dun.de", + "http", + None, + ), + ( + "https://faß.de", + "https://xn--fa-hia.de", + "faß.de", + b"xn--fa-hia.de", + "https", + None, + ), + ( + "https://βόλος.com:443", + "https://xn--nxasmm1c.com:443", + "βόλος.com", + b"xn--nxasmm1c.com", + "https", + None, + ), + ( + "http://ශ්‍රී.com:444", + "http://xn--10cl1a0b660p.com:444", + "ශ්‍රී.com", + b"xn--10cl1a0b660p.com", + "http", + 444, + ), + ( + "https://نامه‌ای.com:4433", + "https://xn--mgba3gch31f060k.com:4433", + "نامه‌ای.com", + b"xn--mgba3gch31f060k.com", + "https", + 4433, + ), + ], + ids=[ + "http_with_port", + "unicode_tr46_compat", + "https_without_port", + "https_with_port", + "http_with_custom_port", + "https_with_custom_port", + ], +) +def test_idna_url(given, idna, host, raw_host, scheme, port): + url = httpx.URL(given) + assert url == httpx.URL(idna) + assert url.host == host + assert url.raw_host == raw_host + assert url.scheme == scheme + assert url.port == port + + +# Tests for IPv6 hostname support. def test_ipv6_url(): @@ -380,6 +435,15 @@ def test_ipv6_url(): assert url.netloc == b"[::ffff:192.168.0.1]:5678" +@pytest.mark.parametrize("host", ["[::ffff:192.168.0.1]", "::ffff:192.168.0.1"]) +def test_ipv6_url_from_raw_url(host): + url = httpx.URL(scheme="https", host=host, port=443, path="/") + + assert url.host == "::ffff:192.168.0.1" + assert url.netloc == b"[::ffff:192.168.0.1]" + assert str(url) == "https://[::ffff:192.168.0.1]/" + + @pytest.mark.parametrize( "url_str", [ @@ -395,30 +459,3 @@ def test_ipv6_url_copy_with_host(url_str, new_host): assert url.host == "::ffff:192.168.0.1" assert url.netloc == b"[::ffff:192.168.0.1]:1234" assert str(url) == "http://[::ffff:192.168.0.1]:1234" - - -@pytest.mark.parametrize("host", ["[::ffff:192.168.0.1]", "::ffff:192.168.0.1"]) -def test_ipv6_url_from_raw_url(host): - url = httpx.URL(scheme="https", host=host, port=443, path="/") - - assert url.host == "::ffff:192.168.0.1" - assert url.netloc == b"[::ffff:192.168.0.1]" - assert str(url) == "https://[::ffff:192.168.0.1]/" - - -def test_resolution_error_1833(): - """ - See https://github.com/encode/httpx/issues/1833 - """ - url = httpx.URL("https://example.com/?[]") - assert url.join("/") == "https://example.com/" - - -def test_url_raw_compatibility(): - url = httpx.URL("https://www.example.com/path") - scheme, host, port, raw_path = url.raw - - assert scheme == b"https" - assert host == b"www.example.com" - assert port is None - assert raw_path == b"/path"