# 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) == []