import pytest
from urllib.parse import SplitResult

from yarl import URL


def test_inheritance():
    with pytest.raises(TypeError) as ctx:

        class MyURL(URL):  # type: ignore[misc]
            pass

    assert (
        "Inheriting a class "
        "<class 'test_url.test_inheritance.<locals>.MyURL'> "
        "from URL is forbidden" == str(ctx.value)
    )


def test_str_subclass():
    class S(str):
        pass

    assert str(URL(S("http://example.com"))) == "http://example.com"


def test_is():
    u1 = URL("http://example.com")
    u2 = URL(u1)
    assert u1 is u2


def test_bool():
    assert URL("http://example.com")
    assert not URL()
    assert not URL("")


def test_absolute_url_without_host():
    with pytest.raises(ValueError):
        URL("http://:8080/")


def test_url_is_not_str():
    url = URL("http://example.com")
    assert not isinstance(url, str)


def test_str():
    url = URL("http://example.com:8888/path/to?a=1&b=2")
    assert str(url) == "http://example.com:8888/path/to?a=1&b=2"


def test_repr():
    url = URL("http://example.com")
    assert "URL('http://example.com')" == repr(url)


def test_origin():
    url = URL("http://user:password@example.com:8888/path/to?a=1&b=2")
    assert URL("http://example.com:8888") == url.origin()


def test_origin_nonascii():
    url = URL("http://user:password@историк.рф:8888/path/to?a=1&b=2")
    assert str(url.origin()) == "http://xn--h1aagokeh.xn--p1ai:8888"


def test_origin_ipv6():
    url = URL("http://user:password@[::1]:8888/path/to?a=1&b=2")
    assert str(url.origin()) == "http://[::1]:8888"


def test_origin_not_absolute_url():
    url = URL("/path/to?a=1&b=2")
    with pytest.raises(ValueError):
        url.origin()


def test_origin_no_scheme():
    url = URL("//user:password@example.com:8888/path/to?a=1&b=2")
    with pytest.raises(ValueError):
        url.origin()


def test_drop_dots():
    u = URL("http://example.com/path/../to")
    assert str(u) == "http://example.com/to"


def test_abs_cmp():
    assert URL("http://example.com:8888") == URL("http://example.com:8888")
    assert URL("http://example.com:8888/") == URL("http://example.com:8888/")
    assert URL("http://example.com:8888/") == URL("http://example.com:8888")
    assert URL("http://example.com:8888") == URL("http://example.com:8888/")


def test_abs_hash():
    url = URL("http://example.com:8888")
    url_trailing = URL("http://example.com:8888/")
    assert hash(url) == hash(url_trailing)


# properties


def test_scheme():
    url = URL("http://example.com")
    assert "http" == url.scheme


def test_raw_user():
    url = URL("http://user@example.com")
    assert "user" == url.raw_user


def test_raw_user_non_ascii():
    url = URL("http://вася@example.com")
    assert "%D0%B2%D0%B0%D1%81%D1%8F" == url.raw_user


def test_no_user():
    url = URL("http://example.com")
    assert url.user is None


def test_user_non_ascii():
    url = URL("http://вася@example.com")
    assert "вася" == url.user


def test_raw_password():
    url = URL("http://user:password@example.com")
    assert "password" == url.raw_password


def test_raw_password_non_ascii():
    url = URL("http://user:пароль@example.com")
    assert "%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" == url.raw_password


def test_password_non_ascii():
    url = URL("http://user:пароль@example.com")
    assert "пароль" == url.password


def test_password_without_user():
    url = URL("http://:password@example.com")
    assert url.user is None
    assert "password" == url.password


def test_user_empty_password():
    url = URL("http://user:@example.com")
    assert "user" == url.user
    assert "" == url.password


def test_raw_host():
    url = URL("http://example.com")
    assert "example.com" == url.raw_host


def test_raw_host_non_ascii():
    url = URL("http://историк.рф")
    assert "xn--h1aagokeh.xn--p1ai" == url.raw_host


def test_host_non_ascii():
    url = URL("http://историк.рф")
    assert "историк.рф" == url.host


def test_localhost():
    url = URL("http://[::1]")
    assert "::1" == url.host


def test_host_with_underscore():
    url = URL("http://abc_def.com")
    assert "abc_def.com" == url.host


def test_raw_host_when_port_is_specified():
    url = URL("http://example.com:8888")
    assert "example.com" == url.raw_host


def test_raw_host_from_str_with_ipv4():
    url = URL("http://127.0.0.1:80")
    assert url.raw_host == "127.0.0.1"


def test_raw_host_from_str_with_ipv6():
    url = URL("http://[::1]:80")
    assert url.raw_host == "::1"


def test_authority_full() -> None:
    url = URL("http://user:passwd@host.com:8080/path")
    assert url.raw_authority == "user:passwd@host.com:8080"
    assert url.authority == "user:passwd@host.com:8080"


def test_authority_short() -> None:
    url = URL("http://host.com/path")
    assert url.raw_authority == "host.com"


def test_authority_full_nonasci() -> None:
    url = URL("http://ваня:пароль@айдеко.рф:8080/path")
    assert url.raw_authority == (
        "%D0%B2%D0%B0%D0%BD%D1%8F:%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C@"
        "xn--80aidohy.xn--p1ai:8080"
    )
    assert url.authority == "ваня:пароль@айдеко.рф:8080"


def test_lowercase():
    url = URL("http://gitHUB.com")
    assert url.raw_host == "github.com"
    assert url.host == url.raw_host


def test_lowercase_nonascii():
    url = URL("http://Айдеко.Рф")
    assert url.raw_host == "xn--80aidohy.xn--p1ai"
    assert url.host == "айдеко.рф"


def test_compressed_ipv6():
    url = URL("http://[1DEC:0:0:0::1]")
    assert url.raw_host == "1dec::1"
    assert url.host == url.raw_host


def test_ipv6_zone():
    url = URL("http://[fe80::822a:a8ff:fe49:470c%тест%42]:123")
    assert url.raw_host == "fe80::822a:a8ff:fe49:470c%тест%42"
    assert url.host == url.raw_host


def test_ipv4_zone():
    # I'm unsure if it is correct.
    url = URL("http://1.2.3.4%тест%42:123")
    assert url.raw_host == "1.2.3.4%тест%42"
    assert url.host == url.raw_host


def test_port_for_explicit_port():
    url = URL("http://example.com:8888")
    assert 8888 == url.port


def test_port_for_implicit_port():
    url = URL("http://example.com")
    assert 80 == url.port


def test_port_for_relative_url():
    url = URL("/path/to")
    assert url.port is None


def test_port_for_unknown_scheme():
    url = URL("unknown://example.com")
    assert url.port is None


def test_explicit_port_for_explicit_port():
    url = URL("http://example.com:8888")
    assert 8888 == url.explicit_port


def test_explicit_port_for_implicit_port():
    url = URL("http://example.com")
    assert url.explicit_port is None


def test_explicit_port_for_relative_url():
    url = URL("/path/to")
    assert url.explicit_port is None


def test_explicit_port_for_unknown_scheme():
    url = URL("unknown://example.com")
    assert url.explicit_port is None


def test_raw_path_string_empty():
    url = URL("http://example.com")
    assert "/" == url.raw_path


def test_raw_path():
    url = URL("http://example.com/path/to")
    assert "/path/to" == url.raw_path


def test_raw_path_non_ascii():
    url = URL("http://example.com/путь/сюда")
    assert "/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%8E%D0%B4%D0%B0" == url.raw_path


def test_path_non_ascii():
    url = URL("http://example.com/путь/сюда")
    assert "/путь/сюда" == url.path


def test_path_with_spaces():
    url = URL("http://example.com/a b/test")
    assert "/a b/test" == url.path

    url = URL("http://example.com/a b")
    assert "/a b" == url.path


def test_raw_path_for_empty_url():
    url = URL()
    assert "" == url.raw_path


def test_raw_path_for_colon_and_at():
    url = URL("http://example.com/path:abc@123")
    assert url.raw_path == "/path:abc@123"


def test_raw_query_string():
    url = URL("http://example.com?a=1&b=2")
    assert url.raw_query_string == "a=1&b=2"


def test_raw_query_string_non_ascii():
    url = URL("http://example.com?б=в&ю=к")
    assert url.raw_query_string == "%D0%B1=%D0%B2&%D1%8E=%D0%BA"


def test_query_string_non_ascii():
    url = URL("http://example.com?б=в&ю=к")
    assert url.query_string == "б=в&ю=к"


def test_path_qs():
    url = URL("http://example.com/")
    assert url.path_qs == "/"
    url = URL("http://example.com/?б=в&ю=к")
    assert url.path_qs == "/?б=в&ю=к"
    url = URL("http://example.com/path?б=в&ю=к")
    assert url.path_qs == "/path?б=в&ю=к"


def test_raw_path_qs():
    url = URL("http://example.com/")
    assert url.raw_path_qs == "/"
    url = URL("http://example.com/?б=в&ю=к")
    assert url.raw_path_qs == "/?%D0%B1=%D0%B2&%D1%8E=%D0%BA"
    url = URL("http://example.com/path?б=в&ю=к")
    assert url.raw_path_qs == "/path?%D0%B1=%D0%B2&%D1%8E=%D0%BA"
    url = URL("http://example.com/путь?a=1&b=2")
    assert url.raw_path_qs == "/%D0%BF%D1%83%D1%82%D1%8C?a=1&b=2"


def test_query_string_spaces():
    url = URL("http://example.com?a+b=c+d&e=f+g")
    assert url.query_string == "a b=c d&e=f g"


# raw fragment


def test_raw_fragment_empty():
    url = URL("http://example.com")
    assert "" == url.raw_fragment


def test_raw_fragment():
    url = URL("http://example.com/path#anchor")
    assert "anchor" == url.raw_fragment


def test_raw_fragment_non_ascii():
    url = URL("http://example.com/path#якорь")
    assert "%D1%8F%D0%BA%D0%BE%D1%80%D1%8C" == url.raw_fragment


def test_raw_fragment_safe():
    url = URL("http://example.com/path#a?b/c:d@e")
    assert "a?b/c:d@e" == url.raw_fragment


def test_fragment_non_ascii():
    url = URL("http://example.com/path#якорь")
    assert "якорь" == url.fragment


def test_raw_parts_empty():
    url = URL("http://example.com")
    assert ("/",) == url.raw_parts


def test_raw_parts():
    url = URL("http://example.com/path/to")
    assert ("/", "path", "to") == url.raw_parts


def test_raw_parts_without_path():
    url = URL("http://example.com")
    assert ("/",) == url.raw_parts


def test_raw_path_parts_with_2F_in_path():
    url = URL("http://example.com/path%2Fto/three")
    assert ("/", "path%2Fto", "three") == url.raw_parts


def test_raw_path_parts_with_2f_in_path():
    url = URL("http://example.com/path%2fto/three")
    assert ("/", "path%2Fto", "three") == url.raw_parts


def test_raw_parts_for_relative_path():
    url = URL("path/to")
    assert ("path", "to") == url.raw_parts


def test_raw_parts_for_relative_path_starting_from_slash():
    url = URL("/path/to")
    assert ("/", "path", "to") == url.raw_parts


def test_raw_parts_for_relative_double_path():
    url = URL("path/to")
    assert url.raw_parts == url.raw_parts


def test_parts_for_empty_url():
    url = URL()
    assert ("",) == url.raw_parts


def test_raw_parts_non_ascii():
    url = URL("http://example.com/путь/сюда")
    assert (
        "/",
        "%D0%BF%D1%83%D1%82%D1%8C",
        "%D1%81%D1%8E%D0%B4%D0%B0",
    ) == url.raw_parts


def test_parts_non_ascii():
    url = URL("http://example.com/путь/сюда")
    assert ("/", "путь", "сюда") == url.parts


def test_name_for_empty_url():
    url = URL()
    assert "" == url.raw_name


def test_raw_name():
    url = URL("http://example.com/path/to#frag")
    assert "to" == url.raw_name


def test_raw_name_root():
    url = URL("http://example.com/#frag")
    assert "" == url.raw_name


def test_raw_name_root2():
    url = URL("http://example.com")
    assert "" == url.raw_name


def test_raw_name_root3():
    url = URL("http://example.com/")
    assert "" == url.raw_name


def test_relative_raw_name():
    url = URL("path/to")
    assert "to" == url.raw_name


def test_relative_raw_name_starting_from_slash():
    url = URL("/path/to")
    assert "to" == url.raw_name


def test_relative_raw_name_slash():
    url = URL("/")
    assert "" == url.raw_name


def test_name_non_ascii():
    url = URL("http://example.com/путь")
    assert url.name == "путь"


def test_plus_in_path():
    url = URL("http://example.com/test/x+y%2Bz/:+%2B/")
    assert "/test/x+y+z/:++/" == url.path


def test_nonascii_in_qs():
    url = URL("http://example.com")
    url2 = url.with_query({"f\xf8\xf8": "f\xf8\xf8"})
    assert "http://example.com/?f%C3%B8%C3%B8=f%C3%B8%C3%B8" == str(url2)


def test_percent_encoded_in_qs():
    url = URL("http://example.com")
    url2 = url.with_query({"k%cf%80": "v%cf%80"})
    assert str(url2) == "http://example.com/?k%25cf%2580=v%25cf%2580"
    assert url2.raw_query_string == "k%25cf%2580=v%25cf%2580"
    assert url2.query_string == "k%cf%80=v%cf%80"
    assert url2.query == {"k%cf%80": "v%cf%80"}


# modifiers


def test_parent_raw_path():
    url = URL("http://example.com/path/to")
    assert url.parent.raw_path == "/path"


def test_parent_raw_parts():
    url = URL("http://example.com/path/to")
    assert url.parent.raw_parts == ("/", "path")


def test_double_parent_raw_path():
    url = URL("http://example.com/path/to")
    assert url.parent.parent.raw_path == "/"


def test_empty_parent_raw_path():
    url = URL("http://example.com/")
    assert url.parent.parent.raw_path == "/"


def test_empty_parent_raw_path2():
    url = URL("http://example.com")
    assert url.parent.parent.raw_path == "/"


def test_clear_fragment_on_getting_parent():
    url = URL("http://example.com/path/to#frag")
    assert URL("http://example.com/path") == url.parent


def test_clear_fragment_on_getting_parent_toplevel():
    url = URL("http://example.com/#frag")
    assert URL("http://example.com/") == url.parent


def test_clear_query_on_getting_parent():
    url = URL("http://example.com/path/to?a=b")
    assert URL("http://example.com/path") == url.parent


def test_clear_query_on_getting_parent_toplevel():
    url = URL("http://example.com/?a=b")
    assert URL("http://example.com/") == url.parent


# truediv


def test_div_root():
    url = URL("http://example.com")
    assert str(url / "path" / "to") == "http://example.com/path/to"


def test_div_root_with_slash():
    url = URL("http://example.com/")
    assert str(url / "path" / "to") == "http://example.com/path/to"


def test_div():
    url = URL("http://example.com/path")
    assert str(url / "to") == "http://example.com/path/to"


def test_div_with_slash():
    url = URL("http://example.com/path/")
    assert str(url / "to") == "http://example.com/path/to"


def test_div_path_starting_from_slash_is_forbidden():
    url = URL("http://example.com/path/")
    with pytest.raises(ValueError):
        url / "/to/others"


def test_div_cleanup_query_and_fragment():
    url = URL("http://example.com/path?a=1#frag")
    assert str(url / "to") == "http://example.com/path/to"


def test_div_for_empty_url():
    url = URL() / "a"
    assert url.raw_parts == ("a",)


def test_div_for_relative_url():
    url = URL("a") / "b"
    assert url.raw_parts == ("a", "b")


def test_div_for_relative_url_started_with_slash():
    url = URL("/a") / "b"
    assert url.raw_parts == ("/", "a", "b")


def test_div_non_ascii():
    url = URL("http://example.com/сюда")
    url2 = url / "туда"
    assert url2.path == "/сюда/туда"
    assert url2.raw_path == "/%D1%81%D1%8E%D0%B4%D0%B0/%D1%82%D1%83%D0%B4%D0%B0"
    assert url2.parts == ("/", "сюда", "туда")
    assert url2.raw_parts == (
        "/",
        "%D1%81%D1%8E%D0%B4%D0%B0",
        "%D1%82%D1%83%D0%B4%D0%B0",
    )


def test_div_percent_encoded():
    url = URL("http://example.com/path")
    url2 = url / "%cf%80"
    assert url2.path == "/path/%cf%80"
    assert url2.raw_path == "/path/%25cf%2580"
    assert url2.parts == ("/", "path", "%cf%80")
    assert url2.raw_parts == ("/", "path", "%25cf%2580")


def test_div_with_colon_and_at():
    url = URL("http://example.com/base") / "path:abc@123"
    assert url.raw_path == "/base/path:abc@123"


def test_div_with_dots():
    url = URL("http://example.com/base") / "../path/./to"
    assert url.raw_path == "/path/to"


# with_path


def test_with_path():
    url = URL("http://example.com")
    url2 = url.with_path("/test")
    assert str(url2) == "http://example.com/test"
    assert url2.raw_path == "/test"
    assert url2.path == "/test"


def test_with_path_nonascii():
    url = URL("http://example.com")
    url2 = url.with_path("/π")
    assert str(url2) == "http://example.com/%CF%80"
    assert url2.raw_path == "/%CF%80"
    assert url2.path == "/π"


def test_with_path_percent_encoded():
    url = URL("http://example.com")
    url2 = url.with_path("/%cf%80")
    assert str(url2) == "http://example.com/%25cf%2580"
    assert url2.raw_path == "/%25cf%2580"
    assert url2.path == "/%cf%80"


def test_with_path_encoded():
    url = URL("http://example.com")
    url2 = url.with_path("/test", encoded=True)
    assert str(url2) == "http://example.com/test"
    assert url2.raw_path == "/test"
    assert url2.path == "/test"


def test_with_path_encoded_nonascii():
    url = URL("http://example.com")
    url2 = url.with_path("/π", encoded=True)
    assert str(url2) == "http://example.com/π"
    assert url2.raw_path == "/π"
    assert url2.path == "/π"


def test_with_path_encoded_percent_encoded():
    url = URL("http://example.com")
    url2 = url.with_path("/%cf%80", encoded=True)
    assert str(url2) == "http://example.com/%cf%80"
    assert url2.raw_path == "/%cf%80"
    assert url2.path == "/π"


def test_with_path_dots():
    url = URL("http://example.com")
    assert str(url.with_path("/test/.")) == "http://example.com/test/"


def test_with_path_relative():
    url = URL("/path")
    assert str(url.with_path("/new")) == "/new"


def test_with_path_query():
    url = URL("http://example.com?a=b")
    assert str(url.with_path("/test")) == "http://example.com/test"


def test_with_path_fragment():
    url = URL("http://example.com#frag")
    assert str(url.with_path("/test")) == "http://example.com/test"


def test_with_path_empty():
    url = URL("http://example.com/test")
    assert str(url.with_path("")) == "http://example.com"


def test_with_path_leading_slash():
    url = URL("http://example.com")
    assert url.with_path("test").path == "/test"


# with_fragment


def test_with_fragment():
    url = URL("http://example.com")
    url2 = url.with_fragment("frag")
    assert str(url2) == "http://example.com/#frag"
    assert url2.raw_fragment == "frag"
    assert url2.fragment == "frag"


def test_with_fragment_safe():
    url = URL("http://example.com")
    u2 = url.with_fragment("a:b?c@d/e")
    assert str(u2) == "http://example.com/#a:b?c@d/e"


def test_with_fragment_non_ascii():
    url = URL("http://example.com")
    url2 = url.with_fragment("фрагм")
    assert url2.raw_fragment == "%D1%84%D1%80%D0%B0%D0%B3%D0%BC"
    assert url2.fragment == "фрагм"


def test_with_fragment_percent_encoded():
    url = URL("http://example.com")
    url2 = url.with_fragment("%cf%80")
    assert str(url2) == "http://example.com/#%25cf%2580"
    assert url2.raw_fragment == "%25cf%2580"
    assert url2.fragment == "%cf%80"


def test_with_fragment_None():
    url = URL("http://example.com/path#frag")
    url2 = url.with_fragment(None)
    assert str(url2) == "http://example.com/path"


def test_with_fragment_None_matching():
    url = URL("http://example.com/path")
    url2 = url.with_fragment(None)
    assert url is url2


def test_with_fragment_matching():
    url = URL("http://example.com/path#frag")
    url2 = url.with_fragment("frag")
    assert url is url2


def test_with_fragment_bad_type():
    url = URL("http://example.com")
    with pytest.raises(TypeError):
        url.with_fragment(123)


# with_name


def test_with_name():
    url = URL("http://example.com/a/b")
    assert url.raw_parts == ("/", "a", "b")
    url2 = url.with_name("c")
    assert url2.raw_parts == ("/", "a", "c")
    assert url2.parts == ("/", "a", "c")
    assert url2.raw_path == "/a/c"
    assert url2.path == "/a/c"


def test_with_name_for_naked_path():
    url = URL("http://example.com")
    url2 = url.with_name("a")
    assert url2.raw_parts == ("/", "a")


def test_with_name_for_relative_path():
    url = URL("a")
    url2 = url.with_name("b")
    assert url2.raw_parts == ("b",)


def test_with_name_for_relative_path2():
    url = URL("a/b")
    url2 = url.with_name("c")
    assert url2.raw_parts == ("a", "c")


def test_with_name_for_relative_path_starting_from_slash():
    url = URL("/a")
    url2 = url.with_name("b")
    assert url2.raw_parts == ("/", "b")


def test_with_name_for_relative_path_starting_from_slash2():
    url = URL("/a/b")
    url2 = url.with_name("c")
    assert url2.raw_parts == ("/", "a", "c")


def test_with_name_empty():
    url = URL("http://example.com/path/to").with_name("")
    assert str(url) == "http://example.com/path/"


def test_with_name_non_ascii():
    url = URL("http://example.com/path").with_name("путь")
    assert url.path == "/путь"
    assert url.raw_path == "/%D0%BF%D1%83%D1%82%D1%8C"
    assert url.parts == ("/", "путь")
    assert url.raw_parts == ("/", "%D0%BF%D1%83%D1%82%D1%8C")


def test_with_name_percent_encoded():
    url = URL("http://example.com/path")
    url2 = url.with_name("%cf%80")
    assert url2.raw_parts == ("/", "%25cf%2580")
    assert url2.parts == ("/", "%cf%80")
    assert url2.raw_path == "/%25cf%2580"
    assert url2.path == "/%cf%80"


def test_with_name_with_slash():
    with pytest.raises(ValueError):
        URL("http://example.com").with_name("a/b")


def test_with_name_non_str():
    with pytest.raises(TypeError):
        URL("http://example.com").with_name(123)


def test_with_name_within_colon_and_at():
    url = URL("http://example.com/oldpath").with_name("path:abc@123")
    assert url.raw_path == "/path:abc@123"


def test_with_name_dot():
    with pytest.raises(ValueError):
        URL("http://example.com").with_name(".")


def test_with_name_double_dot():
    with pytest.raises(ValueError):
        URL("http://example.com").with_name("..")


# is_absolute


def test_is_absolute_for_relative_url():
    url = URL("/path/to")
    assert not url.is_absolute()


def test_is_absolute_for_absolute_url():
    url = URL("http://example.com")
    assert url.is_absolute()


def test_is_non_absolute_for_empty_url():
    url = URL()
    assert not url.is_absolute()


def test_is_non_absolute_for_empty_url2():
    url = URL("")
    assert not url.is_absolute()


def test_is_absolute_path_starting_from_double_slash():
    url = URL("//www.python.org")
    assert url.is_absolute()


# is_default_port


def test_is_default_port_for_relative_url():
    url = URL("/path/to")
    assert not url.is_default_port()


def test_is_default_port_for_absolute_url_without_port():
    url = URL("http://example.com")
    assert url.is_default_port()


def test_is_default_port_for_absolute_url_with_default_port():
    url = URL("http://example.com:80")
    assert url.is_default_port()


def test_is_default_port_for_absolute_url_with_nondefault_port():
    url = URL("http://example.com:8080")
    assert not url.is_default_port()


def test_is_default_port_for_unknown_scheme():
    url = URL("unknown://example.com:8080")
    assert not url.is_default_port()


#


def test_no_scheme():
    url = URL("example.com")
    assert url.raw_host is None
    assert url.raw_path == "example.com"
    assert str(url) == "example.com"


def test_no_scheme2():
    url = URL("example.com/a/b")
    assert url.raw_host is None
    assert url.raw_path == "example.com/a/b"
    assert str(url) == "example.com/a/b"


def test_from_non_allowed():
    with pytest.raises(TypeError):
        URL(1234)


def test_from_idna():
    url = URL("http://xn--jxagkqfkduily1i.eu")
    assert "http://xn--jxagkqfkduily1i.eu" == str(url)
    url = URL("http://xn--einla-pqa.de/")  # needs idna 2008
    assert "http://xn--einla-pqa.de/" == str(url)


def test_to_idna():
    url = URL("http://εμπορικόσήμα.eu")
    assert "http://xn--jxagkqfkduily1i.eu" == str(url)
    url = URL("http://einlaß.de/")
    assert "http://xn--einla-pqa.de/" == str(url)


def test_from_ascii_login():
    url = URL("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/")
    assert ("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") == str(url)


def test_from_non_ascii_login():
    url = URL("http://вася@host:1234/")
    assert ("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") == str(url)


def test_from_ascii_login_and_password():
    url = URL(
        "http://"
        "%D0%B2%D0%B0%D1%81%D1%8F"
        ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C"
        "@host:1234/"
    )
    assert (
        "http://"
        "%D0%B2%D0%B0%D1%81%D1%8F"
        ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C"
        "@host:1234/"
    ) == str(url)


def test_from_non_ascii_login_and_password():
    url = URL("http://вася:пароль@host:1234/")
    assert (
        "http://"
        "%D0%B2%D0%B0%D1%81%D1%8F"
        ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C"
        "@host:1234/"
    ) == str(url)


def test_from_ascii_path():
    url = URL("http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0")
    assert (
        "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
    ) == str(url)


def test_from_ascii_path_lower_case():
    url = URL("http://example.com/" "%d0%bf%d1%83%d1%82%d1%8c/%d1%82%d1%83%d0%b4%d0%b0")
    assert (
        "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
    ) == str(url)


def test_from_non_ascii_path():
    url = URL("http://example.com/путь/туда")
    assert (
        "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
    ) == str(url)


def test_bytes():
    url = URL("http://example.com/путь/туда")
    assert (
        b"http://example.com/%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
        == bytes(url)
    )


def test_from_ascii_query_parts():
    url = URL(
        "http://example.com/"
        "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC"
        "=%D0%B7%D0%BD%D0%B0%D1%87"
    )
    assert (
        "http://example.com/"
        "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC"
        "=%D0%B7%D0%BD%D0%B0%D1%87"
    ) == str(url)


def test_from_non_ascii_query_parts():
    url = URL("http://example.com/?парам=знач")
    assert (
        "http://example.com/"
        "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC"
        "=%D0%B7%D0%BD%D0%B0%D1%87"
    ) == str(url)


def test_from_non_ascii_query_parts2():
    url = URL("http://example.com/?п=з&ю=б")
    assert "http://example.com/?%D0%BF=%D0%B7&%D1%8E=%D0%B1" == str(url)


def test_from_ascii_fragment():
    url = URL("http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82")
    assert (
        "http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82"
    ) == str(url)


def test_from_bytes_with_non_ascii_fragment():
    url = URL("http://example.com/#фрагмент")
    assert (
        "http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82"
    ) == str(url)


def test_to_str():
    url = URL("http://εμπορικόσήμα.eu/")
    assert "http://xn--jxagkqfkduily1i.eu/" == str(url)


def test_to_str_long():
    url = URL(
        "https://host-12345678901234567890123456789012345678901234567890" "-name:8888/"
    )
    expected = (
        "https://host-"
        "12345678901234567890123456789012345678901234567890"
        "-name:8888/"
    )
    assert expected == str(url)


def test_decoding_with_2F_in_path():
    url = URL("http://example.com/path%2Fto")
    assert "http://example.com/path%2Fto" == str(url)
    assert url == URL(str(url))


def test_decoding_with_26_and_3D_in_query():
    url = URL("http://example.com/?%26=%3D")
    assert "http://example.com/?%26=%3D" == str(url)
    assert url == URL(str(url))


def test_fragment_only_url():
    url = URL("#frag")
    assert str(url) == "#frag"


def test_url_from_url():
    url = URL("http://example.com")
    assert URL(url) == url
    assert URL(url).raw_parts == ("/",)


def test_lowercase_scheme():
    url = URL("HTTP://example.com")
    assert str(url) == "http://example.com"


def test_str_for_empty_url():
    url = URL()
    assert "" == str(url)


def test_parent_for_empty_url():
    url = URL()
    assert url is url.parent


def test_empty_value_for_query():
    url = URL("http://example.com/path").with_query({"a": ""})
    assert str(url) == "http://example.com/path?a="


def test_none_value_for_query():
    with pytest.raises(TypeError):
        URL("http://example.com/path").with_query({"a": None})


def test_decode_pct_in_path():
    url = URL("http://www.python.org/%7Eguido")
    assert "http://www.python.org/~guido" == str(url)


def test_decode_pct_in_path_lower_case():
    url = URL("http://www.python.org/%7eguido")
    assert "http://www.python.org/~guido" == str(url)


# join


def test_join():
    base = URL("http://www.cwi.nl/%7Eguido/Python.html")
    url = URL("FAQ.html")
    url2 = base.join(url)
    assert str(url2) == "http://www.cwi.nl/~guido/FAQ.html"


def test_join_absolute():
    base = URL("http://www.cwi.nl/%7Eguido/Python.html")
    url = URL("//www.python.org/%7Eguido")
    url2 = base.join(url)
    assert str(url2) == "http://www.python.org/~guido"


def test_join_non_url():
    base = URL("http://example.com")
    with pytest.raises(TypeError):
        base.join("path/to")


NORMAL = [
    ("g:h", "g:h"),
    ("g", "http://a/b/c/g"),
    ("./g", "http://a/b/c/g"),
    ("g/", "http://a/b/c/g/"),
    ("/g", "http://a/g"),
    ("//g", "http://g"),
    ("?y", "http://a/b/c/d;p?y"),
    ("g?y", "http://a/b/c/g?y"),
    ("#s", "http://a/b/c/d;p?q#s"),
    ("g#s", "http://a/b/c/g#s"),
    ("g?y#s", "http://a/b/c/g?y#s"),
    (";x", "http://a/b/c/;x"),
    ("g;x", "http://a/b/c/g;x"),
    ("g;x?y#s", "http://a/b/c/g;x?y#s"),
    ("", "http://a/b/c/d;p?q"),
    (".", "http://a/b/c/"),
    ("./", "http://a/b/c/"),
    ("..", "http://a/b/"),
    ("../", "http://a/b/"),
    ("../g", "http://a/b/g"),
    ("../..", "http://a/"),
    ("../../", "http://a/"),
    ("../../g", "http://a/g"),
]


@pytest.mark.parametrize("url,expected", NORMAL)
def test_join_from_rfc_3986_normal(url, expected):
    # test case from https://tools.ietf.org/html/rfc3986.html#section-5.4
    base = URL("http://a/b/c/d;p?q")
    url = URL(url)
    expected = URL(expected)
    assert base.join(url) == expected


ABNORMAL = [
    ("../../../g", "http://a/g"),
    ("../../../../g", "http://a/g"),
    ("/./g", "http://a/g"),
    ("/../g", "http://a/g"),
    ("g.", "http://a/b/c/g."),
    (".g", "http://a/b/c/.g"),
    ("g..", "http://a/b/c/g.."),
    ("..g", "http://a/b/c/..g"),
    ("./../g", "http://a/b/g"),
    ("./g/.", "http://a/b/c/g/"),
    ("g/./h", "http://a/b/c/g/h"),
    ("g/../h", "http://a/b/c/h"),
    ("g;x=1/./y", "http://a/b/c/g;x=1/y"),
    ("g;x=1/../y", "http://a/b/c/y"),
    ("g?y/./x", "http://a/b/c/g?y/./x"),
    ("g?y/../x", "http://a/b/c/g?y/../x"),
    ("g#s/./x", "http://a/b/c/g#s/./x"),
    ("g#s/../x", "http://a/b/c/g#s/../x"),
]


@pytest.mark.parametrize("url,expected", ABNORMAL)
def test_join_from_rfc_3986_abnormal(url, expected):
    # test case from https://tools.ietf.org/html/rfc3986.html#section-5.4.2
    base = URL("http://a/b/c/d;p?q")
    url = URL(url)
    expected = URL(expected)
    assert base.join(url) == expected


def test_split_result_non_decoded():
    with pytest.raises(ValueError):
        URL(SplitResult("http", "example.com", "path", "qs", "frag"))


def test_human_repr():
    url = URL("http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг")
    s = url.human_repr()
    assert URL(s) == url
    assert s == "http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг"


def test_human_repr_defaults():
    url = URL("путь")
    s = url.human_repr()
    assert s == "путь"


def test_human_repr_default_port():
    url = URL("http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг")
    s = url.human_repr()
    assert URL(s) == url
    assert s == "http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг"


def test_human_repr_ipv6():
    url = URL("http://[::1]:8080/path")
    s = url.human_repr()
    url2 = URL(s)
    assert url2 == url
    assert url2.host == "::1"
    assert s == "http://[::1]:8080/path"


def test_human_repr_delimiters():
    url = URL.build(
        scheme="http",
        user=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
        password=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
        host="хост.домен",
        port=8080,
        path="/ !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
        query={
            " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~": " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
        },
        fragment=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
    )
    s = url.human_repr()
    assert URL(s) == url
    assert (
        s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~"
        ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~"
        "@хост.домен:8080"
        "/ !\"%23$%25&'()*+,-./:;<=>%3F@[\\]^_`{|}~"
        "? !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~"
        "= !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~"
        "# !\"#$%25&'()*+,-./:;<=>?@[\\]^_`{|}~"
    )


def test_human_repr_non_printable():
    url = URL.build(
        scheme="http",
        user="вася\n\xad\u200b",
        password="пароль\n\xad\u200b",
        host="хост.домен",
        port=8080,
        path="/путь\n\xad\u200b",
        query={"арг\n\xad\u200b": "вал\n\xad\u200b"},
        fragment="фраг\n\xad\u200b",
    )
    s = url.human_repr()
    assert URL(s) == url
    assert (
        s == "http://вася%0A%C2%AD%E2%80%8B:пароль%0A%C2%AD%E2%80%8B"
        "@хост.домен:8080"
        "/путь%0A%C2%AD%E2%80%8B"
        "?арг%0A%C2%AD%E2%80%8B=вал%0A%C2%AD%E2%80%8B"
        "#фраг%0A%C2%AD%E2%80%8B"
    )


# relative


def test_relative():
    url = URL("http://user:pass@example.com:8080/path?a=b#frag")
    rel = url.relative()
    assert str(rel) == "/path?a=b#frag"


def test_relative_is_relative():
    url = URL("http://user:pass@example.com:8080/path?a=b#frag")
    rel = url.relative()
    assert not rel.is_absolute()


def test_relative_abs_parts_are_removed():
    url = URL("http://user:pass@example.com:8080/path?a=b#frag")
    rel = url.relative()
    assert not rel.scheme
    assert not rel.user
    assert not rel.password
    assert not rel.host
    assert not rel.port


def test_relative_fails_on_rel_url():
    with pytest.raises(ValueError):
        URL("/path?a=b#frag").relative()


def test_slash_and_question_in_query():
    u = URL("http://example.com/path?http://example.com/p?a#b")
    assert u.query_string == "http://example.com/p?a"


def test_slash_and_question_in_fragment():
    u = URL("http://example.com/path#http://example.com/p?a")
    assert u.fragment == "http://example.com/p?a"


def test_requoting():
    u = URL("http://127.0.0.1/?next=http%3A//example.com/")
    assert u.raw_query_string == "next=http://example.com/"
    assert str(u) == "http://127.0.0.1/?next=http://example.com/"
