Files
unios-tts/tests/test_normalize.py
Shaman 82c306ff69 init
2026-10-01 07:38:01 +03:00

133 lines
5.5 KiB
Python

import pytest
from app.normalize import mark_pause_delimiters, normalize_common
from app.segmentation import prepare_segments
from app.ssml import PAUSE_DELIM as P, build_ssml, strip_sentinels
DELIMS = "([{«“<)]}»>\"'`*_~"
# 5.1/5.2: разделительные символы удаляются, в паузообразующих позициях
# остаётся sentinel (НЕ запятая). Проверяем инварианты, а не литеральные запятые.
@pytest.mark.parametrize("text, expected_pauses", [
("скажи, что именно интересует (мир, техника, курсы валют), и я поищу.", 1),
('он сказал "сейчас проверю" и ушёл', 2),
('он сказал: "привет"', 0),
("мы сходим (надо)", 1),
('вот текст (важно)"', 1),
("он сказал **важно** слово", 2),
("слово *курсив* конец", 2),
("это _важно_ для дела", 2),
("список ~зачёркнут~ конец", 2),
("код `inline` конец", 2),
("тема «мир» конец", 2),
("сравнение x < 5 > 3 конец", 2),
("это {фигурные} и [квадратные] скобки", 4),
("слово 'вот это' конец", 2),
])
def test_delimiters_removed_pause_is_sentinel(text, expected_pauses):
result = mark_pause_delimiters(text)
for ch in DELIMS:
assert ch not in result, f"символ {ch!r} не удалён из {result!r}"
assert result.count(P) == expected_pauses
@pytest.mark.parametrize("text, expected", [
("мы сходим (надо)", f"мы сходим {P} надо"),
('вот текст (важно)"', f"вот текст {P} важно"),
("он сказал **важно** слово", f"он сказал {P} важно {P} слово"),
('он сказал: "привет"', "он сказал: привет"),
("погода в твоём городе?), и я поищу.", "погода в твоём городе?, и я поищу."),
])
def test_delimiter_pause_positions(text, expected):
assert mark_pause_delimiters(text) == expected
@pytest.mark.parametrize("text", [
"д'Катт и O'Neill пришли",
])
def test_apostrophes_inside_words_untouched(text):
assert mark_pause_delimiters(text) == text
@pytest.mark.parametrize("text", [
"текст (важно).",
"текст (важно), конец",
"текст [важно]!",
"(важно)",
])
def test_no_delimiter_chars_left(text):
result = mark_pause_delimiters(text)
for ch in DELIMS:
assert ch not in result
@pytest.mark.parametrize("text", [
"текст (важно).",
"текст (важно), конец",
"текст (важно)! и ещё (так) конец",
])
def test_no_dangling_artifacts(text):
# Sentinel не добавляет запятых; после удаления артефактов не остаётся.
result = mark_pause_delimiters(text)
assert ",," not in result
assert not result.lstrip().startswith(",")
assert ",." not in result
def test_line_boundaries():
text = "(в начале строки) текст\nтекст (в конце строки)\n(снова) конец"
result = mark_pause_delimiters(text)
for ch in "()":
assert ch not in result
assert P in result
clean = strip_sentinels(result)
assert "снова" in clean and "конец" in clean and "текст" in clean
def test_multiline_delimiters_processed_in_every_line():
text = "первая (строка) тут\nвторая «строка» тут"
result = mark_pause_delimiters(text)
assert "(" not in result and "«" not in result and "»" not in result
clean = strip_sentinels(result)
assert "строка" in clean and "тут" in clean
assert P in result
def test_english_text_same_rule():
segments = prepare_segments("The (parenthetical) works")
ssml = build_ssml(segments)
assert "<break" in ssml
assert "parenthetical" in ssml
assert "(" not in ssml and ")" not in ssml
def test_bug_example_pauses_before_and_after_parentheses():
text = ("скажи, что именно интересует (мир, техника, курсы валют, "
"погода в твоём городе?), и я поищу.")
segments = prepare_segments(text)
stripped = strip_sentinels(" ".join(s.text for s in segments))
assert "(" not in stripped and ")" not in stripped
assert ",," not in stripped
assert "интересует" in stripped and "город" in stripped
# Единственная паузная граница — от открывающей скобки перед «мир»;
# закрывающая скобка перед запятой границы не создаёт.
ssml = build_ssml(segments)
assert ssml.count("<break") == 1
assert P not in ssml
def test_pause_delim_becomes_break_in_ssml():
segments = prepare_segments("он сказал **важно** слово")
ssml = build_ssml(segments)
assert ssml.count("<break") == 2
assert P not in ssml
def test_underscore_not_verbalized_before_regional_normalization():
segments = prepare_segments("это _важно_ для дела")
joined = strip_sentinels(" ".join(s.text for s in segments))
assert "_" not in joined
assert "подчеркивание" not in joined.lower()
assert "подчёркивание" not in joined.lower()