"""Tests for CUCM dial-plan wildcard pattern matching.""" import pytest from mcp_cucm_axl.route_plan import _pattern_matches_number, _wildcard_to_regex class TestLiteralPatterns: def test_exact_match(self): assert _pattern_matches_number("1001", "1001") def test_no_match(self): assert not _pattern_matches_number("1001", "1002") def test_escaped_plus(self): assert _pattern_matches_number(r"\+15551234567", "+15551234567") assert not _pattern_matches_number(r"\+15551234567", "15551234567") class TestXWildcard: def test_X_matches_any_digit(self): assert _pattern_matches_number("XXXX", "1234") assert _pattern_matches_number("XXXX", "9999") def test_X_only_matches_digits(self): assert not _pattern_matches_number("XXXX", "abc1") assert not _pattern_matches_number("XXXX", "12") # too short assert not _pattern_matches_number("XXXX", "12345") # too long def test_X_mixed_with_literal(self): assert _pattern_matches_number("9XXXX", "91234") assert not _pattern_matches_number("9XXXX", "81234") class TestBangWildcard: def test_bang_matches_one_or_more(self): assert _pattern_matches_number("9!", "91") assert _pattern_matches_number("9!", "915551234567") def test_bang_requires_at_least_one(self): assert not _pattern_matches_number("9!", "9") class TestCharacterClass: def test_class_matches_any_in_set(self): assert _pattern_matches_number("[2-9]XXX", "2000") assert _pattern_matches_number("[2-9]XXX", "9999") def test_class_excludes_outside_set(self): assert not _pattern_matches_number("[2-9]XXX", "1000") assert not _pattern_matches_number("[2-9]XXX", "0000") class TestDotTerminator: def test_dot_is_zero_width(self): # CUCM's '.' is a marker for digit-discard, not a regex char assert _pattern_matches_number("9.911", "9911") assert _pattern_matches_number("10.911", "10911") def test_dot_with_X_after(self): assert _pattern_matches_number("9.[2-9]XXXXXXXXX", "92085551234") class TestAtPattern: def test_at_matches_any_digits(self): # @ would normally apply a route filter; we treat it as "any digits" assert _pattern_matches_number("9.@", "915551234567") assert _pattern_matches_number("\\+.@", "+15551234567") class TestEdgeCases: def test_invalid_regex_returns_false(self): # An unbalanced bracket should not raise result = _pattern_matches_number("[", "1") assert result is False def test_empty_pattern(self): assert _pattern_matches_number("", "") assert not _pattern_matches_number("", "1") def test_regex_anchors(self): # Make sure we don't match a substring assert not _pattern_matches_number("911", "1911") assert not _pattern_matches_number("911", "9111") class TestRegexConversion: def test_X_to_digit_class(self): assert _wildcard_to_regex("X") == r"^\d$" def test_bang_to_one_or_more_digits(self): assert _wildcard_to_regex("!") == r"^\d+$" def test_anchored(self): regex = _wildcard_to_regex("9XXX") assert regex.startswith("^") assert regex.endswith("$")