117 lines
4.1 KiB
Python
117 lines
4.1 KiB
Python
# Copyright 2026 Umbra Tools (umbratools.com)
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from umbraaudio import library
|
|
|
|
|
|
def _speaker(name: str = "Distorted Voice", **overrides) -> dict:
|
|
sp = {
|
|
"primary_name": name,
|
|
"aliases": [],
|
|
"gender": "Female",
|
|
"accent": "canadian",
|
|
"vocal_traits": ["raspy"],
|
|
"distortion_effects": ["hard_clip"],
|
|
"is_narrator": False,
|
|
"is_group": False,
|
|
"description": "test speaker",
|
|
}
|
|
sp.update(overrides)
|
|
return sp
|
|
|
|
|
|
class TestAddSpeakers:
|
|
def test_adds_and_copies_voice_ref(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
voices = temp_dir / "libvoices"
|
|
voices.mkdir(parents=True)
|
|
|
|
src = temp_dir / "src_distorted_voice_ref.wav"
|
|
src.write_bytes(b"RIFFDATAFORVOICE")
|
|
|
|
res = library.add_speakers(
|
|
[_speaker()],
|
|
source_project="TestProject",
|
|
voice_refs={"Distorted Voice": src},
|
|
db_path=db,
|
|
voices_dir=voices,
|
|
)
|
|
assert res["added"] == ["Distorted Voice"]
|
|
assert (voices / "distorted_voice_ref.wav").exists()
|
|
assert (voices / "distorted_voice_ref.wav").read_bytes() == b"RIFFDATAFORVOICE"
|
|
|
|
rows = library.list_speakers(db_path=db)
|
|
assert len(rows) == 1
|
|
assert rows[0]["primary_name"] == "Distorted Voice"
|
|
assert "distorted_voice_ref.wav" in rows[0]["voice_ref_path"]
|
|
|
|
def test_idempotent_duplicate(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
voices = temp_dir / "lv"
|
|
voices.mkdir(parents=True)
|
|
src = temp_dir / "narrator_ref.wav"
|
|
src.write_bytes(b"REF")
|
|
|
|
library.add_speakers(
|
|
[_speaker("Narrator", is_narrator=True)],
|
|
"P", {"Narrator": src}, db_path=db, voices_dir=voices,
|
|
)
|
|
res = library.add_speakers(
|
|
[_speaker("Narrator", is_narrator=True)],
|
|
"P", {"Narrator": src}, db_path=db, voices_dir=voices,
|
|
)
|
|
assert res["already"] == ["Narrator"]
|
|
assert len(library.list_speakers(db_path=db)) == 1
|
|
|
|
def test_skips_speaker_without_ref(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
res = library.add_speakers(
|
|
[_speaker()], "P", {}, db_path=db, voices_dir=temp_dir,
|
|
)
|
|
assert res["added"] == ["Distorted Voice"]
|
|
assert library.list_speakers(db_path=db)[0]["voice_ref_path"] is None
|
|
|
|
|
|
class TestAddNames:
|
|
def test_adds_records(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
res = library.add_names(
|
|
[{"name": "Kainda", "phonetic": "KAYN-dah", "source": "user",
|
|
"common": False, "confirmed": True}],
|
|
source_project="P",
|
|
db_path=db,
|
|
)
|
|
assert res["added"] == ["Kainda"]
|
|
rows = library.list_names(db_path=db)
|
|
assert rows[0]["name"] == "Kainda"
|
|
assert rows[0]["phonetic"] == "KAYN-dah"
|
|
assert rows[0]["confirmed"] == 1
|
|
|
|
def test_idempotent_duplicate(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
rec = {"name": "Kainda", "phonetic": "KAYN-dah"}
|
|
library.add_names([rec], "P", db_path=db)
|
|
res = library.add_names([rec], "P", db_path=db)
|
|
assert res["already"] == ["Kainda"]
|
|
assert len(library.list_names(db_path=db)) == 1
|
|
|
|
|
|
class TestDelete:
|
|
def test_delete_speaker(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
library.add_speakers([_speaker()], "P", {}, db_path=db, voices_dir=temp_dir)
|
|
sid = library.list_speakers(db_path=db)[0]["id"]
|
|
assert library.delete_speaker(sid, db_path=db) is True
|
|
assert library.list_speakers(db_path=db) == []
|
|
|
|
def test_delete_name(self, temp_dir: Path):
|
|
db = temp_dir / "voice_registry.db"
|
|
library.add_names([{"name": "Kainda"}], "P", db_path=db)
|
|
nid = library.list_names(db_path=db)[0]["id"]
|
|
assert library.delete_name(nid, db_path=db) is True
|
|
assert library.list_names(db_path=db) == []
|