-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_phone_utils.py
More file actions
112 lines (89 loc) · 4.66 KB
/
Copy pathtest_phone_utils.py
File metadata and controls
112 lines (89 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""Unit tests for phone number validation and masking."""
from hungrycall.phone_utils import (
mask_phone,
mask_phones_in_text,
normalize_e164,
redact_specific_phone,
validate_e164,
)
# Fictional throughout this file (AGENTS.md: examples only with fictional
# numbers) - never the operator's real callback number.
FICTIONAL_CALLBACK = "+4917612345678"
def test_validate_e164_valid():
assert validate_e164("+491701234567") is True
assert validate_e164("+15551234567") is True
assert validate_e164("+442079460999") is True
def test_validate_e164_invalid():
assert validate_e164("01701234567") is False
assert validate_e164("12345") is False
assert validate_e164("") is False
assert validate_e164("invalid_phone") is False
def test_normalize_e164():
assert normalize_e164("01701234567") == "+491701234567"
assert normalize_e164("00491701234567") == "+491701234567"
assert normalize_e164("+49 170 1234567") == "+491701234567"
def test_mask_phone():
masked = mask_phone("+491701234567")
assert "170" in masked or "+49" in masked
assert "1234" not in masked # Middle numbers masked
assert "567" in masked # Suffix kept for callback reference
assert "•••" in masked
def test_mask_phone_inside_api_text():
text = "Callback +491701234567; second +49 30 1234567."
masked = mask_phones_in_text(text)
assert "+491701234567" not in masked
assert "+49 30 1234567" not in masked
assert masked.endswith("••• ••••567; second +493 ••• ••••567.")
def test_national_format_numbers_are_masked_in_text():
"""Field trial 2026-08-11: a dictated national-format number (fictional
example here, e.g. '01701234567') sailed unmasked through transcripts
because only +49-style forms were recognised."""
from hungrycall.phone_utils import mask_phones_in_text
masked = mask_phones_in_text("dann nehme ich die 01701234567 als Rückrufnummer")
assert "01701234567" not in masked
assert "•••" in masked
spaced = mask_phones_in_text("unter 0170 123 45 67 erreichbar")
assert "123" not in spaced.replace("•", "")
# Harmless digits stay: prices, years, times, house numbers, order ids.
for harmless in ("17 Euro", "um 20:45 Uhr", "im Jahr 2026",
"Hausnummer 12", "Bestellnummer 4711"):
assert mask_phones_in_text(harmless) == harmless
def test_spelled_out_digit_words_of_a_known_number_are_redacted():
"""Field trial 2026-08-11: the voice agent read the requester's own
callback number aloud as individual German digit words, which neither
PHONE_CANDIDATE_REGEX (redact_specific_phone) nor mask_phones_in_text
(no contiguous digit run) recognised as the same number."""
text = "Die Rückrufnummer ist plus vier neun, eins sieben sechs, eins zwei drei, vier fünf sechs, sieben acht."
redacted = redact_specific_phone(text, FICTIONAL_CALLBACK)
assert "vier" not in redacted
assert "neun" not in redacted
assert "[REDACTED-REQUESTER-CALLBACK]" in redacted
def test_spelled_out_digit_words_split_across_a_transcript_turn_header():
"""The exact 2026-08-11 shape: CALL-E's STT ended one turn mid-number, so
LiveCallClient._transcript_from_turns() reconstructed it as two lines,
each carrying its own "[mm:ss] SPEAKER: " header in between the digit
words."""
text = (
"[01:10] BOT: Die direkte Rückrufnummer ist plus vier neun,\n"
"[01:15] BOT: eins sieben sechs, eins zwei drei, vier fünf sechs, sieben acht."
)
redacted = redact_specific_phone(text, FICTIONAL_CALLBACK)
assert "[REDACTED-REQUESTER-CALLBACK]" in redacted
assert "vier" not in redacted
assert "sieben" not in redacted
# The rest of the sentence, and the turn headers themselves, survive.
assert "[01:10] BOT:" in redacted
assert "Die direkte Rückrufnummer ist" in redacted
def test_spelled_out_digits_of_a_different_number_are_left_alone():
"""Only the KNOWN target number is redacted -- an unrelated spoken digit
sequence (e.g. a price or another party's number) is not touched, unlike
a general number-word parser would risk."""
text = "Das macht acht Euro fünfzig, und die Uhrzeit ist neun Uhr."
assert redact_specific_phone(text, FICTIONAL_CALLBACK) == text
def test_digit_form_redaction_is_unaffected_by_the_spelled_out_fix():
"""No regression: the pre-existing compact-digit redaction path still
works exactly as before."""
text = f"Rückruf unter {FICTIONAL_CALLBACK} jederzeit möglich."
redacted = redact_specific_phone(text, FICTIONAL_CALLBACK)
assert FICTIONAL_CALLBACK not in redacted
assert "[REDACTED-REQUESTER-CALLBACK]" in redacted