Files
VoiceStudio/tests/test_text_polish.py
d58010fe1b feat(dictation): rebuild to Wispr-Flow quality — live waveform, streaming commits, honest insertion, polished text (#888)
* feat(dictation): rebuild to instant-feedback quality — waveform, streaming commits, honest insertion, text polish

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(changelog): dictation rebuild entry

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(lint): Array.from over new Array(n) — oxlint no-array-constructor

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 17:57:56 +05:30

91 lines
3.4 KiB
Python

"""
Unit tests for services/text_polish.py — the deterministic polish applied to
every dictation `final` (dictation v2): leading capital (Latin scripts only),
terminal punctuation (incl. CJK forms), whitespace cleanup. Pure function, no
model — so these pin exact strings.
"""
import os
import pytest
os.environ.setdefault("OMNIVOICE_MODEL", "test")
os.environ.setdefault("OMNIVOICE_DISABLE_FILE_LOG", "1")
from services.text_polish import polish_text # noqa: E402
# ── Latin: capitalization + terminal punctuation ─────────────────────────────
@pytest.mark.parametrize("raw,polished", [
("hello world", "Hello world."),
("Hello world", "Hello world."),
("what time is it?", "What time is it?"), # already terminated
("wow!", "Wow!"),
("wait…", "Wait…"), # ellipsis is terminal
("42 is the answer", "42 is the answer."), # non-letter start untouched
("école ouverte", "École ouverte."), # Latin-1 accents capitalize
("čapek wrote robots", "Čapek wrote robots."), # Latin Extended
])
def test_latin_basics(raw, polished):
assert polish_text(raw) == polished
def test_whitespace_collapsed_and_stripped():
assert polish_text(" hello world ") == "Hello world."
assert polish_text("a \t b") == "A b." # mixed space/tab run
def test_dangling_separator_swapped_for_stop():
# ASR often stops mid-breath on a comma — swap it, don't stack ",.".
assert polish_text("see you tomorrow,") == "See you tomorrow."
assert polish_text("first; second;") == "First; second."
def test_terminal_behind_closing_quote_respected():
assert polish_text('he said "stop."') == 'He said "stop."'
assert polish_text("(done!)") == "(done!)"
assert polish_text('he said "stop"') == 'He said "stop".'
# ── CJK: passthrough (no capitalization) + fullwidth stop ────────────────────
def test_cjk_already_punctuated_passes_through():
assert polish_text("你好,世界。") == "你好,世界。"
assert polish_text("すごい!") == "すごい!"
assert polish_text("本当ですか?") == "本当ですか?"
def test_cjk_gets_fullwidth_stop():
assert polish_text("你好世界") == "你好世界。"
assert polish_text("ありがとう") == "ありがとう。"
def test_cjk_dangling_comma_swapped():
assert polish_text("你好,") == "你好。"
# ── Non-Latin alphabets: no capitalization, still get a stop ─────────────────
def test_cyrillic_and_greek_not_capitalized():
assert polish_text("привет мир") == "привет мир."
assert polish_text("γεια σου") == "γεια σου."
# ── Edge cases ───────────────────────────────────────────────────────────────
def test_empty_and_whitespace_only():
assert polish_text("") == ""
assert polish_text(" ") == ""
assert polish_text("\t \t") == ""
assert polish_text(",") == "" # dangling-only → empty
def test_idempotent():
for raw in ["hello world", "你好世界", "привет", "What?!", "a, b,"]:
once = polish_text(raw)
assert polish_text(once) == once