115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
# Copyright 2026 Umbra Tools (umbratools.com)
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from __future__ import annotations
|
|
|
|
from umbraaudio.web.routes import (
|
|
_extract_proper_nouns,
|
|
_lowercase_words,
|
|
_mid_sentence_counts,
|
|
_proper_name_candidates,
|
|
_speaker_name_words,
|
|
)
|
|
|
|
_TEXT = (
|
|
"Kainda walked in. Princess Kainda Murphy smiled. The Warbots roared. "
|
|
"They went there and they left after what happened. "
|
|
"Wow, that is odd. Additionally, I have a plan. "
|
|
"Captain Weston spoke. Weston is a friend. The ship is the Deal Hunter. "
|
|
"Gisfrid arrived. Karel waited. It was a good deal, the captain said to the princess."
|
|
)
|
|
|
|
_SPEAKERS = [
|
|
{"primary_name": "Kainda Walters Foster Murphy", "aliases": ["Princess Kainda"]},
|
|
{"primary_name": "Captain Weston", "aliases": []},
|
|
{"primary_name": "Deal Hunter", "aliases": []},
|
|
{"primary_name": "Gisfrid", "aliases": []},
|
|
]
|
|
|
|
|
|
def _records() -> dict:
|
|
return {
|
|
"Kainda": {"phonetic": "KAYN-duh", "source": "user", "confirmed": True, "common": False},
|
|
}
|
|
|
|
|
|
def test_extract_proper_nouns_flattens_multiword() -> None:
|
|
nouns = {entry["name"]: entry["count"] for entry in _extract_proper_nouns(_TEXT)}
|
|
assert "Princess Kainda Murphy" not in nouns
|
|
assert "Captain Weston" not in nouns
|
|
assert nouns["Kainda"] == 2
|
|
assert nouns["Murphy"] == 1
|
|
assert nouns["Weston"] == 2
|
|
|
|
|
|
def test_extract_proper_nouns_excludes_titles_and_stopwords() -> None:
|
|
nouns = {entry["name"] for entry in _extract_proper_nouns(_TEXT)}
|
|
assert "Captain" not in nouns
|
|
assert "Princess" not in nouns
|
|
assert "The" not in nouns
|
|
assert "It" not in nouns
|
|
|
|
|
|
def test_lowercase_words_only_literal_lowercase() -> None:
|
|
words = _lowercase_words(_TEXT)
|
|
assert "they" in words
|
|
assert "after" in words
|
|
assert "deal" in words
|
|
assert "kainda" not in words
|
|
assert "murphy" not in words
|
|
|
|
|
|
def test_mid_sentence_counts() -> None:
|
|
counts = _mid_sentence_counts(_TEXT, {"Kainda", "Weston", "Wow", "Gisfrid"})
|
|
assert counts["Kainda"] == 1
|
|
assert counts["Weston"] >= 1
|
|
assert counts.get("Wow", 0) == 0
|
|
assert counts.get("Gisfrid", 0) == 0
|
|
|
|
|
|
def test_speaker_name_words_excludes_descriptors() -> None:
|
|
words = _speaker_name_words(_SPEAKERS, _lowercase_words(_TEXT))
|
|
assert "kainda" in words
|
|
assert "murphy" in words
|
|
assert "weston" in words
|
|
assert "gisfrid" in words
|
|
assert "captain" not in words
|
|
assert "princess" not in words
|
|
|
|
|
|
def test_proper_name_candidates_keeps_names() -> None:
|
|
kept = {
|
|
entry["name"]: entry
|
|
for entry in _proper_name_candidates(
|
|
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, _records()
|
|
)
|
|
}
|
|
for name in ("Kainda", "Murphy", "Warbots", "Weston", "Hunter", "Gisfrid"):
|
|
assert name in kept, f"{name} should be kept"
|
|
assert kept["Kainda"]["is_speaker"] is True
|
|
assert kept["Murphy"]["is_speaker"] is True
|
|
assert kept["Gisfrid"]["is_speaker"] is True
|
|
|
|
|
|
def test_proper_name_candidates_drops_prose() -> None:
|
|
kept = {
|
|
entry["name"]
|
|
for entry in _proper_name_candidates(
|
|
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, _records()
|
|
)
|
|
}
|
|
for name in ("They", "After", "What", "That", "Wow", "Additionally", "Deal", "Karel"):
|
|
assert name not in kept, f"{name} should be dropped"
|
|
|
|
|
|
def test_proper_name_candidates_keeps_confirmed_name() -> None:
|
|
records = _records()
|
|
records["Karel"] = {"phonetic": "KAH-rel", "source": "user", "confirmed": True, "common": False}
|
|
kept = {
|
|
entry["name"]
|
|
for entry in _proper_name_candidates(
|
|
_extract_proper_nouns(_TEXT), _TEXT, _SPEAKERS, records
|
|
)
|
|
}
|
|
assert "Karel" in kept
|