Tests for check_handling/regex_constants
This commit is contained in:
1
tests/unit/check_handling/__init__.py
Normal file
1
tests/unit/check_handling/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Unit tests for check_handling module."""
|
||||
336
tests/unit/check_handling/test_regex_constants.py
Normal file
336
tests/unit/check_handling/test_regex_constants.py
Normal file
@@ -0,0 +1,336 @@
|
||||
"""
|
||||
Unit tests for regex_constants module.
|
||||
|
||||
Tests all regex patterns defined in the check_handling.regex_constants module.
|
||||
"""
|
||||
|
||||
import re
|
||||
import pytest
|
||||
from corelibs.check_handling.regex_constants import (
|
||||
compile_re,
|
||||
EMAIL_BASIC_REGEX,
|
||||
DOMAIN_WITH_LOCALHOST_REGEX,
|
||||
DOMAIN_WITH_LOCALHOST_PORT_REGEX,
|
||||
DOMAIN_REGEX,
|
||||
)
|
||||
|
||||
|
||||
class TestCompileRe:
|
||||
"""Test cases for the compile_re function."""
|
||||
|
||||
def test_compile_re_returns_pattern(self) -> None:
|
||||
"""Test that compile_re returns a compiled regex Pattern object."""
|
||||
pattern = compile_re(r"test")
|
||||
assert isinstance(pattern, re.Pattern)
|
||||
|
||||
def test_compile_re_with_verbose_flag(self) -> None:
|
||||
"""Test that compile_re compiles with VERBOSE flag."""
|
||||
# Verbose mode allows whitespace and comments in regex
|
||||
verbose_regex = r"""
|
||||
\d+ # digits
|
||||
\s+ # whitespace
|
||||
"""
|
||||
pattern = compile_re(verbose_regex)
|
||||
assert pattern.match("123 ")
|
||||
assert not pattern.match("abc")
|
||||
|
||||
def test_compile_re_simple_pattern(self) -> None:
|
||||
"""Test compile_re with a simple pattern."""
|
||||
pattern = compile_re(r"^\d{3}$")
|
||||
assert pattern.match("123")
|
||||
assert not pattern.match("12")
|
||||
assert not pattern.match("1234")
|
||||
|
||||
|
||||
class TestEmailBasicRegex:
|
||||
"""Test cases for EMAIL_BASIC_REGEX pattern."""
|
||||
|
||||
@pytest.fixture
|
||||
def email_pattern(self) -> re.Pattern[str]:
|
||||
"""Fixture that returns compiled email regex pattern."""
|
||||
return compile_re(EMAIL_BASIC_REGEX)
|
||||
|
||||
@pytest.mark.parametrize("valid_email", [
|
||||
"user@example.com",
|
||||
"test.user@example.com",
|
||||
"user+tag@example.co.uk",
|
||||
"first.last@subdomain.example.com",
|
||||
"user123@test-domain.com",
|
||||
"a@example.com",
|
||||
"user_name@example.com",
|
||||
"user-name@example.com",
|
||||
"user@sub.domain.example.com",
|
||||
"test!#$%&'*+-/=?^_`{|}~@example.com",
|
||||
"1234567890@example.com",
|
||||
"user@example-domain.com",
|
||||
"user@domain.co",
|
||||
# Regex allows these (even if not strictly RFC compliant):
|
||||
"user.@example.com", # ends with dot before @
|
||||
"user..name@example.com", # consecutive dots in local part
|
||||
])
|
||||
def test_valid_emails(
|
||||
self, email_pattern: re.Pattern[str], valid_email: str
|
||||
) -> None:
|
||||
"""Test that valid email addresses match the pattern."""
|
||||
assert email_pattern.match(valid_email), (
|
||||
f"Failed to match valid email: {valid_email}"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("invalid_email", [
|
||||
"", # empty string
|
||||
"@example.com", # missing local part
|
||||
"user@", # missing domain
|
||||
"user", # no @ symbol
|
||||
"user@.com", # domain starts with dot
|
||||
"user@domain", # no TLD
|
||||
"user @example.com", # space in local part
|
||||
"user@exam ple.com", # space in domain
|
||||
".user@example.com", # starts with dot
|
||||
"user@-example.com", # domain starts with hyphen
|
||||
"user@example-.com", # domain part ends with hyphen
|
||||
"user@example.c", # TLD too short (1 char)
|
||||
"user@example.toolong", # TLD too long (>6 chars)
|
||||
"user@@example.com", # double @
|
||||
"user@example@com", # multiple @
|
||||
"user@.example.com", # domain starts with dot
|
||||
"user@example.com.", # ends with dot
|
||||
"user@123.456.789.012", # numeric TLD not allowed
|
||||
])
|
||||
def test_invalid_emails(
|
||||
self, email_pattern: re.Pattern[str], invalid_email: str
|
||||
) -> None:
|
||||
"""Test that invalid email addresses do not match the pattern."""
|
||||
assert not email_pattern.match(invalid_email), (
|
||||
f"Incorrectly matched invalid email: {invalid_email}"
|
||||
)
|
||||
|
||||
def test_email_max_local_part_length(
|
||||
self, email_pattern: re.Pattern[str]
|
||||
) -> None:
|
||||
"""Test email with maximum local part length (64 characters)."""
|
||||
# Local part can be up to 64 chars (first char + 63 more)
|
||||
local_part = "a" * 64
|
||||
email = f"{local_part}@example.com"
|
||||
assert email_pattern.match(email)
|
||||
|
||||
def test_email_exceeds_local_part_length(
|
||||
self, email_pattern: re.Pattern[str]
|
||||
) -> None:
|
||||
"""Test email exceeding maximum local part length."""
|
||||
# 65 characters should not match
|
||||
local_part = "a" * 65
|
||||
email = f"{local_part}@example.com"
|
||||
assert not email_pattern.match(email)
|
||||
|
||||
|
||||
class TestDomainWithLocalhostRegex:
|
||||
"""Test cases for DOMAIN_WITH_LOCALHOST_REGEX pattern."""
|
||||
|
||||
@pytest.fixture
|
||||
def domain_localhost_pattern(self) -> re.Pattern[str]:
|
||||
"""Fixture that returns compiled domain with localhost regex pattern."""
|
||||
return compile_re(DOMAIN_WITH_LOCALHOST_REGEX)
|
||||
|
||||
@pytest.mark.parametrize("valid_domain", [
|
||||
"localhost",
|
||||
"example.com",
|
||||
"subdomain.example.com",
|
||||
"sub.domain.example.com",
|
||||
"test-domain.com",
|
||||
"example.co.uk",
|
||||
"a.com",
|
||||
"test123.example.com",
|
||||
"my-site.example.org",
|
||||
"multi.level.subdomain.example.com",
|
||||
])
|
||||
def test_valid_domains(
|
||||
self, domain_localhost_pattern: re.Pattern[str], valid_domain: str
|
||||
) -> None:
|
||||
"""Test that valid domains (including localhost) match the pattern."""
|
||||
assert domain_localhost_pattern.match(valid_domain), (
|
||||
f"Failed to match valid domain: {valid_domain}"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("invalid_domain", [
|
||||
"", # empty string
|
||||
"example", # no TLD
|
||||
"-example.com", # starts with hyphen
|
||||
"example-.com", # ends with hyphen
|
||||
".example.com", # starts with dot
|
||||
"example.com.", # ends with dot
|
||||
"example..com", # consecutive dots
|
||||
"exam ple.com", # space in domain
|
||||
"example.c", # TLD too short
|
||||
"localhost:8080", # port not allowed in this pattern
|
||||
"example.com:8080", # port not allowed in this pattern
|
||||
"@example.com", # invalid character
|
||||
"example@com", # invalid character
|
||||
])
|
||||
def test_invalid_domains(
|
||||
self, domain_localhost_pattern: re.Pattern[str], invalid_domain: str
|
||||
) -> None:
|
||||
"""Test that invalid domains do not match the pattern."""
|
||||
assert not domain_localhost_pattern.match(invalid_domain), (
|
||||
f"Incorrectly matched invalid domain: {invalid_domain}"
|
||||
)
|
||||
|
||||
|
||||
class TestDomainWithLocalhostPortRegex:
|
||||
"""Test cases for DOMAIN_WITH_LOCALHOST_PORT_REGEX pattern."""
|
||||
|
||||
@pytest.fixture
|
||||
def domain_localhost_port_pattern(self) -> re.Pattern[str]:
|
||||
"""Fixture that returns compiled domain and localhost with port pattern."""
|
||||
return compile_re(DOMAIN_WITH_LOCALHOST_PORT_REGEX)
|
||||
|
||||
@pytest.mark.parametrize("valid_domain", [
|
||||
"localhost",
|
||||
"localhost:8080",
|
||||
"localhost:3000",
|
||||
"localhost:80",
|
||||
"localhost:443",
|
||||
"localhost:65535",
|
||||
"example.com",
|
||||
"example.com:8080",
|
||||
"subdomain.example.com:3000",
|
||||
"test-domain.com:443",
|
||||
"example.co.uk",
|
||||
"example.co.uk:8000",
|
||||
"a.com:1",
|
||||
"multi.level.subdomain.example.com:9999",
|
||||
])
|
||||
def test_valid_domains_with_port(
|
||||
self, domain_localhost_port_pattern: re.Pattern[str], valid_domain: str
|
||||
) -> None:
|
||||
"""Test that valid domains with optional ports match the pattern."""
|
||||
assert domain_localhost_port_pattern.match(valid_domain), (
|
||||
f"Failed to match valid domain: {valid_domain}"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("invalid_domain", [
|
||||
"", # empty string
|
||||
"example", # no TLD
|
||||
"-example.com", # starts with hyphen
|
||||
"example-.com", # ends with hyphen
|
||||
".example.com", # starts with dot
|
||||
"example.com.", # ends with dot
|
||||
"localhost:", # port without number
|
||||
"example.com:", # port without number
|
||||
"example.com:abc", # non-numeric port
|
||||
"example.com: 8080", # space before port
|
||||
"example.com:80 80", # space in port
|
||||
"exam ple.com", # space in domain
|
||||
"localhost :8080", # space before colon
|
||||
])
|
||||
def test_invalid_domains_with_port(
|
||||
self,
|
||||
domain_localhost_port_pattern: re.Pattern[str],
|
||||
invalid_domain: str,
|
||||
) -> None:
|
||||
"""Test that invalid domains do not match the pattern."""
|
||||
assert not domain_localhost_port_pattern.match(invalid_domain), (
|
||||
f"Incorrectly matched invalid domain: {invalid_domain}"
|
||||
)
|
||||
|
||||
def test_large_port_number(
|
||||
self, domain_localhost_port_pattern: re.Pattern[str]
|
||||
) -> None:
|
||||
"""Test domain with large port numbers."""
|
||||
assert domain_localhost_port_pattern.match("example.com:65535")
|
||||
# Regex doesn't validate port range
|
||||
assert domain_localhost_port_pattern.match("example.com:99999")
|
||||
|
||||
|
||||
class TestDomainRegex:
|
||||
"""Test cases for DOMAIN_REGEX pattern (no localhost)."""
|
||||
|
||||
@pytest.fixture
|
||||
def domain_pattern(self) -> re.Pattern[str]:
|
||||
"""Fixture that returns compiled domain regex pattern."""
|
||||
return compile_re(DOMAIN_REGEX)
|
||||
|
||||
@pytest.mark.parametrize("valid_domain", [
|
||||
"example.com",
|
||||
"subdomain.example.com",
|
||||
"sub.domain.example.com",
|
||||
"test-domain.com",
|
||||
"example.co.uk",
|
||||
"a.com",
|
||||
"test123.example.com",
|
||||
"my-site.example.org",
|
||||
"multi.level.subdomain.example.com",
|
||||
"example.co",
|
||||
])
|
||||
def test_valid_domains_no_localhost(
|
||||
self, domain_pattern: re.Pattern[str], valid_domain: str
|
||||
) -> None:
|
||||
"""Test that valid domains match the pattern."""
|
||||
assert domain_pattern.match(valid_domain), (
|
||||
f"Failed to match valid domain: {valid_domain}"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("invalid_domain", [
|
||||
"", # empty string
|
||||
"localhost", # localhost not allowed
|
||||
"example", # no TLD
|
||||
"-example.com", # starts with hyphen
|
||||
"example-.com", # ends with hyphen
|
||||
".example.com", # starts with dot
|
||||
"example.com.", # ends with dot
|
||||
"example..com", # consecutive dots
|
||||
"exam ple.com", # space in domain
|
||||
"example.c", # TLD too short
|
||||
"example.com:8080", # port not allowed
|
||||
"@example.com", # invalid character
|
||||
"example@com", # invalid character
|
||||
])
|
||||
def test_invalid_domains_no_localhost(
|
||||
self, domain_pattern: re.Pattern[str], invalid_domain: str
|
||||
) -> None:
|
||||
"""Test that invalid domains do not match the pattern."""
|
||||
assert not domain_pattern.match(invalid_domain), (
|
||||
f"Incorrectly matched invalid domain: {invalid_domain}"
|
||||
)
|
||||
|
||||
def test_localhost_not_allowed(
|
||||
self, domain_pattern: re.Pattern[str]
|
||||
) -> None:
|
||||
"""Test that localhost is explicitly not allowed in DOMAIN_REGEX."""
|
||||
assert not domain_pattern.match("localhost")
|
||||
|
||||
|
||||
class TestRegexPatternConsistency:
|
||||
"""Test cases for consistency across regex patterns."""
|
||||
|
||||
def test_all_patterns_compile(self) -> None:
|
||||
"""Test that all regex patterns can be compiled without errors."""
|
||||
patterns = [
|
||||
EMAIL_BASIC_REGEX,
|
||||
DOMAIN_WITH_LOCALHOST_REGEX,
|
||||
DOMAIN_WITH_LOCALHOST_PORT_REGEX,
|
||||
DOMAIN_REGEX,
|
||||
]
|
||||
for pattern in patterns:
|
||||
compiled = compile_re(pattern)
|
||||
assert isinstance(compiled, re.Pattern)
|
||||
|
||||
def test_domain_patterns_are_strings(self) -> None:
|
||||
"""Test that all regex constants are strings."""
|
||||
assert isinstance(EMAIL_BASIC_REGEX, str)
|
||||
assert isinstance(DOMAIN_WITH_LOCALHOST_REGEX, str)
|
||||
assert isinstance(DOMAIN_WITH_LOCALHOST_PORT_REGEX, str)
|
||||
assert isinstance(DOMAIN_REGEX, str)
|
||||
|
||||
def test_domain_patterns_hierarchy(self) -> None:
|
||||
"""Test that domain patterns follow expected hierarchy."""
|
||||
# DOMAIN_WITH_LOCALHOST_PORT_REGEX should accept everything
|
||||
# DOMAIN_WITH_LOCALHOST_REGEX accepts
|
||||
domain_localhost = compile_re(DOMAIN_WITH_LOCALHOST_REGEX)
|
||||
domain_localhost_port = compile_re(DOMAIN_WITH_LOCALHOST_PORT_REGEX)
|
||||
|
||||
test_cases = ["example.com", "subdomain.example.com", "localhost"]
|
||||
for test_case in test_cases:
|
||||
if domain_localhost.match(test_case):
|
||||
assert domain_localhost_port.match(test_case), (
|
||||
f"{test_case} should match both patterns"
|
||||
)
|
||||
Reference in New Issue
Block a user