mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-08-30 14:37:14 +00:00
134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
import pytest
|
|
import regex
|
|
from pytest_mock import MockerFixture
|
|
|
|
from documents.regex import safe_regex_finditer
|
|
from documents.regex import safe_regex_match
|
|
from documents.regex import safe_regex_search
|
|
from documents.regex import safe_regex_sub
|
|
from documents.regex import validate_regex_pattern
|
|
|
|
|
|
class TestValidateRegexPattern:
|
|
def test_valid_pattern(self) -> None:
|
|
validate_regex_pattern(r"\d+")
|
|
|
|
def test_invalid_pattern_raises(self) -> None:
|
|
with pytest.raises(ValueError):
|
|
validate_regex_pattern(r"[invalid")
|
|
|
|
|
|
class TestSafeRegexSearchAndMatch:
|
|
"""Tests for safe_regex_search and safe_regex_match (same contract)."""
|
|
|
|
@pytest.mark.parametrize(
|
|
("func", "pattern", "text", "expected_group"),
|
|
[
|
|
pytest.param(
|
|
safe_regex_search,
|
|
r"\d+",
|
|
"abc123def",
|
|
"123",
|
|
id="search-match-found",
|
|
),
|
|
pytest.param(
|
|
safe_regex_match,
|
|
r"\d+",
|
|
"123abc",
|
|
"123",
|
|
id="match-match-found",
|
|
),
|
|
],
|
|
)
|
|
def test_match_found(self, func, pattern, text, expected_group) -> None:
|
|
result = func(pattern, text)
|
|
assert result is not None
|
|
assert result.group() == expected_group
|
|
|
|
@pytest.mark.parametrize(
|
|
("func", "pattern", "text"),
|
|
[
|
|
pytest.param(safe_regex_search, r"\d+", "abcdef", id="search-no-match"),
|
|
pytest.param(safe_regex_match, r"\d+", "abc123", id="match-no-match"),
|
|
],
|
|
)
|
|
def test_no_match(self, func, pattern, text) -> None:
|
|
assert func(pattern, text) is None
|
|
|
|
@pytest.mark.parametrize(
|
|
"func",
|
|
[
|
|
pytest.param(safe_regex_search, id="search"),
|
|
pytest.param(safe_regex_match, id="match"),
|
|
],
|
|
)
|
|
def test_invalid_pattern_returns_none(self, func) -> None:
|
|
assert func(r"[invalid", "test") is None
|
|
|
|
@pytest.mark.parametrize(
|
|
"func",
|
|
[
|
|
pytest.param(safe_regex_search, id="search"),
|
|
pytest.param(safe_regex_match, id="match"),
|
|
],
|
|
)
|
|
def test_flags_respected(self, func) -> None:
|
|
assert func(r"abc", "ABC", flags=regex.IGNORECASE) is not None
|
|
|
|
@pytest.mark.parametrize(
|
|
("func", "method_name"),
|
|
[
|
|
pytest.param(safe_regex_search, "search", id="search"),
|
|
pytest.param(safe_regex_match, "match", id="match"),
|
|
],
|
|
)
|
|
def test_timeout_returns_none(
|
|
self,
|
|
func,
|
|
method_name,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
mock_compile = mocker.patch("documents.regex.regex.compile")
|
|
getattr(mock_compile.return_value, method_name).side_effect = TimeoutError
|
|
assert func(r"\d+", "test") is None
|
|
|
|
|
|
class TestSafeRegexSub:
|
|
@pytest.mark.parametrize(
|
|
("pattern", "repl", "text", "expected"),
|
|
[
|
|
pytest.param(r"\d+", "NUM", "abc123def456", "abcNUMdefNUM", id="basic-sub"),
|
|
pytest.param(r"\d+", "NUM", "abcdef", "abcdef", id="no-match"),
|
|
pytest.param(r"abc", "X", "ABC", "X", id="flags"),
|
|
],
|
|
)
|
|
def test_substitution(self, pattern, repl, text, expected) -> None:
|
|
flags = regex.IGNORECASE if pattern == r"abc" else 0
|
|
result = safe_regex_sub(pattern, repl, text, flags=flags)
|
|
assert result == expected
|
|
|
|
def test_invalid_pattern_returns_none(self) -> None:
|
|
assert safe_regex_sub(r"[invalid", "x", "test") is None
|
|
|
|
def test_timeout_returns_none(self, mocker: MockerFixture) -> None:
|
|
mock_compile = mocker.patch("documents.regex.regex.compile")
|
|
mock_compile.return_value.sub.side_effect = TimeoutError
|
|
assert safe_regex_sub(r"\d+", "X", "test") is None
|
|
|
|
|
|
class TestSafeRegexFinditer:
|
|
def test_yields_matches(self) -> None:
|
|
pattern = regex.compile(r"\d+")
|
|
matches = list(safe_regex_finditer(pattern, "a1b22c333"))
|
|
assert [m.group() for m in matches] == ["1", "22", "333"]
|
|
|
|
def test_no_matches(self) -> None:
|
|
pattern = regex.compile(r"\d+")
|
|
assert list(safe_regex_finditer(pattern, "abcdef")) == []
|
|
|
|
def test_timeout_stops_iteration(self, mocker: MockerFixture) -> None:
|
|
mock_pattern = mocker.MagicMock()
|
|
mock_pattern.finditer.side_effect = TimeoutError
|
|
mock_pattern.pattern = r"\d+"
|
|
assert list(safe_regex_finditer(mock_pattern, "test")) == []
|