"""Test Domain."""
# external
import pytest
# local
from validators import ValidationError, domain
@pytest.mark.parametrize(
("value", "rfc_1034", "rfc_2782"),
[
("example.com", False, False),
("exa_mple.com", False, True),
("xn----gtbspbbmkef.xn--p1ai", False, False),
("underscore_subdomain.example.com", False, True),
("something.versicherung", False, False),
("someThing.versicherung.", True, False),
("11.com", False, False),
("3.cn.", True, False),
("_example.com", False, True),
("example_.com", False, True),
("_exa_mple_.com", False, True),
("a.cn", False, False),
("sub1.sub2.sample.co.uk", False, False),
("somerandomexample.xn--fiqs8s", False, False),
("kruter.com.", True, False),
("ber.com", False, False),
],
)
def test_returns_true_on_valid_domain(value: str, rfc_1034: bool, rfc_2782: bool):
"""Test returns true on valid domain."""
assert domain(value, rfc_1034=rfc_1034, rfc_2782=rfc_2782)
@pytest.mark.parametrize(
("value", "consider_tld", "rfc_1034", "rfc_2782"),
[
("example.com", True, False, False),
("exa_mple.com", True, False, True),
("xn----gtbspbbmkef.xn--p1ai", True, False, False),
("underscore_subdomain.example.com", True, False, True),
("someThing.versicherung.", True, True, False),
("11.com", True, False, False),
("3.cn.", True, True, False),
("_example.com", True, False, True),
("example_.com", True, False, True),
("somerandomexample.xn--fiqs8s", True, False, False),
("somerandomexample.onion", True, False, False),
],
)
def test_returns_true_on_valid_top_level_domain(
value: str, consider_tld: bool, rfc_1034: bool, rfc_2782: bool
):
"""Test returns true on valid top level domain."""
assert domain(value, consider_tld=consider_tld, rfc_1034=rfc_1034, rfc_2782=rfc_2782)
@pytest.mark.parametrize(
("value", "rfc_1034", "rfc_2782"),
[
("example.com/.", True, False),
("example.com:4444", False, False),
("example.-com", False, False),
("example.", False, False),
("-example.com", False, False),
("example-.com.", True, False),
("_example.com", False, False),
("_example._com", False, False),
("example_.com", False, False),
("example", False, False),
("example.com!", True, False),
("example?.com", True, False),
("__exa__mple__.com", False, True),
("a......b.com", False, False),
("a.123", False, False),
("foo.ba_r", False, False),
("foo.ba_r", False, True),
("example.co_uk", False, False),
("123.123", False, False),
("123.123.123.", True, False),
("123.123.123.123", False, False),
],
)
def test_returns_failed_validation_on_invalid_domain(value: str, rfc_1034: bool, rfc_2782: bool):
"""Test returns failed validation on invalid domain."""
assert isinstance(domain(value, rfc_1034=rfc_1034, rfc_2782=rfc_2782), ValidationError)
@pytest.mark.parametrize(
("value", "consider_tld", "rfc_1034", "rfc_2782"),
[
("example.266", True, False, False),
("exa_mple.org_", True, False, True),
("xn----gtbspbbmkef.xn-p1ai", True, False, False),
("underscore_subdomain.example.flat", True, False, True),
("someThing.versicherung.reddit.", True, True, False),
("11.twitter", True, False, False),
("3.cnx.", True, True, False),
("_example.#13", True, False, True),
("example_.fo-ul", True, False, True),
("somerandomexample.xn-n-fiqs8s", True, False, False),
],
)
def test_returns_failed_validation_invalid_top_level_domain(
value: str, consider_tld: bool, rfc_1034: bool, rfc_2782: bool
):
"""Test returns failed validation invalid top level domain."""
assert isinstance(
domain(value, consider_tld=consider_tld, rfc_1034=rfc_1034, rfc_2782=rfc_2782),
ValidationError,
)
def _name_of_length(length: int):
"""Build a dotted name of exactly `length` characters, ending with `.com`."""
labels: list[str] = []
remaining = length - len(".com")
while remaining > 0:
size = min(61, remaining)
if remaining - size == 1: # avoid leaving a lone "." behind
size -= 1
labels.append("a" * size)
remaining -= size + 1
name = ".".join(labels) + ".com"
assert len(name) == length
return name
@pytest.mark.parametrize(
"value",
[
# total length: at most 253 characters (RFC 1035)
_name_of_length(253),
# label length: at most 63 characters (RFC 1035)
"a" * 63 + ".com",
# a label may start with a digit (RFC 1123)
"1host.example.com",
# the limit is in octets of the encoded name, not characters: 189 characters
# here, but 225 octets once IDNA-encoded
".".join(["" * 30] * 6) + ".com",
],
)
def test_returns_true_on_domain_within_rfc_length_limits(value: str):
"""Test returns true on domain within RFC length limits."""
assert domain(value)
@pytest.mark.parametrize(
"value",
[
_name_of_length(254),
_name_of_length(255),
# many short, dot-separated labels that exceed 253 characters; see #413
".".join(["kld8MXQh6YalMqKRbfs895gMjW5T4p2EwToPoCSThPHHbXgmXc"] * 4)
+ ".kld8MXQh6YalMqKRbfs895gMjW5T4p2EwToPoCSThPHHbXgmXcab",
"a" * 64 + ".com",
# fewer than 253 characters (220), but 262 octets once IDNA-encoded
".".join(["" * 30] * 7) + ".com",
# the example from #407 (261 characters)
"www." + ".".join(["abcdefghijklmnop"] * 15) + ".fr",
# a label must not start or end with a hyphen
"-host.example.com",
"host-.example.com",
],
)
def test_returns_failed_validation_on_domain_beyond_rfc_limits(value: str):
"""Test returns failed validation on domain beyond RFC limits."""
assert isinstance(domain(value), ValidationError)