mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat(tts-plugin): complete Plugin Architecture refactor
- Normalize Pipeline public API: create_pipeline(plugin_id, *, lang_code, device) - EngineConfig: add lang_code field per Architecture Amendment #1 - Kokoro plugin reads config.lang_code (fixes functional regression) - Static voice catalog in PluginManifest.voices (None = dynamic/VoiceLister) - get_voices() reads from manifest without creating Engine - Remove dead kwargs (sample_rate, auto_download, total_steps) from SuperTonic - Clean up unused imports and dead code in engine implementations - Fix test expectations for VoiceLister (mock overrides) - Add clear_preview_pipelines() for resource management
This commit is contained in:
@@ -1,106 +1,106 @@
|
||||
"""Contract tests for Engine protocol.
|
||||
|
||||
These tests verify that Engine implementations satisfy the architectural requirements:
|
||||
- createSession() returns EngineSession
|
||||
- dispose() is idempotent
|
||||
- After dispose(), createSession() raises EngineError
|
||||
- Engine is thread-safe for createSession()
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from abogen.tts_plugin.engine import Engine, EngineSession
|
||||
from abogen.tts_plugin.errors import EngineError
|
||||
|
||||
from .conftest import FakeEngine, FakeEngineSession
|
||||
|
||||
|
||||
class TestEngineProtocolContract:
|
||||
"""Contract tests for the Engine protocol itself."""
|
||||
|
||||
def test_engine_is_protocol(self) -> None:
|
||||
assert hasattr(Engine, "__protocol_attrs__")
|
||||
|
||||
def test_engine_session_is_protocol(self) -> None:
|
||||
assert hasattr(EngineSession, "__protocol_attrs__")
|
||||
|
||||
def test_fake_engine_satisfies_protocol(self) -> None:
|
||||
engine = FakeEngine()
|
||||
assert isinstance(engine, Engine)
|
||||
|
||||
def test_fake_session_satisfies_protocol(self) -> None:
|
||||
session = FakeEngineSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
|
||||
class TestEngineCreateSessionContract:
|
||||
"""Contract tests for Engine.createSession()."""
|
||||
|
||||
def test_create_session_returns_engine_session(self) -> None:
|
||||
engine = FakeEngine()
|
||||
session = engine.createSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
def test_create_session_returns_new_instance(self) -> None:
|
||||
engine = FakeEngine()
|
||||
session1 = engine.createSession()
|
||||
session2 = engine.createSession()
|
||||
assert session1 is not session2
|
||||
|
||||
def test_create_session_ownership_transfers(self) -> None:
|
||||
"""Architecture spec: Ownership transfers to caller."""
|
||||
engine = FakeEngine()
|
||||
session = engine.createSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
|
||||
class TestEngineDisposeContract:
|
||||
"""Contract tests for Engine.dispose()."""
|
||||
|
||||
def test_dispose_is_idempotent(self) -> None:
|
||||
"""Architecture spec: dispose() is idempotent."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
engine.dispose() # Should not raise
|
||||
|
||||
def test_dispose_never_raises(self) -> None:
|
||||
"""Architecture spec: dispose() never raises exceptions."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose() # Should not raise
|
||||
|
||||
def test_create_session_after_dispose_raises(self) -> None:
|
||||
"""Architecture spec: After dispose(), all methods except dispose() raise EngineError."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
with pytest.raises(EngineError):
|
||||
engine.createSession()
|
||||
|
||||
|
||||
class TestEngineLifecycleContract:
|
||||
"""Contract tests for Engine lifecycle."""
|
||||
|
||||
def test_full_lifecycle(self) -> None:
|
||||
"""Test complete engine lifecycle: create -> sessions -> dispose."""
|
||||
engine = FakeEngine()
|
||||
|
||||
# Create sessions
|
||||
session1 = engine.createSession()
|
||||
session2 = engine.createSession()
|
||||
|
||||
# Use sessions
|
||||
assert isinstance(session1, EngineSession)
|
||||
assert isinstance(session2, EngineSession)
|
||||
|
||||
# Dispose sessions
|
||||
session1.dispose()
|
||||
session2.dispose()
|
||||
|
||||
# Dispose engine
|
||||
engine.dispose()
|
||||
|
||||
def test_engine_disposed_session_raises(self) -> None:
|
||||
"""Architecture spec: After dispose(), all methods except dispose() raise EngineError."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
with pytest.raises(EngineError):
|
||||
engine.createSession()
|
||||
"""Contract tests for Engine protocol.
|
||||
|
||||
These tests verify that Engine implementations satisfy the architectural requirements:
|
||||
- createSession() returns EngineSession
|
||||
- dispose() is idempotent
|
||||
- After dispose(), createSession() raises EngineError
|
||||
- Engine is thread-safe for createSession()
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from abogen.tts_plugin.engine import Engine, EngineSession
|
||||
from abogen.tts_plugin.errors import EngineError
|
||||
|
||||
from .conftest import FakeEngine, FakeEngineSession
|
||||
|
||||
|
||||
class TestEngineProtocolContract:
|
||||
"""Contract tests for the Engine protocol itself."""
|
||||
|
||||
def test_engine_is_protocol(self) -> None:
|
||||
assert hasattr(Engine, "__protocol_attrs__")
|
||||
|
||||
def test_engine_session_is_protocol(self) -> None:
|
||||
assert hasattr(EngineSession, "__protocol_attrs__")
|
||||
|
||||
def test_fake_engine_satisfies_protocol(self) -> None:
|
||||
engine = FakeEngine()
|
||||
assert isinstance(engine, Engine)
|
||||
|
||||
def test_fake_session_satisfies_protocol(self) -> None:
|
||||
session = FakeEngineSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
|
||||
class TestEngineCreateSessionContract:
|
||||
"""Contract tests for Engine.createSession()."""
|
||||
|
||||
def test_create_session_returns_engine_session(self) -> None:
|
||||
engine = FakeEngine()
|
||||
session = engine.createSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
def test_create_session_returns_new_instance(self) -> None:
|
||||
engine = FakeEngine()
|
||||
session1 = engine.createSession()
|
||||
session2 = engine.createSession()
|
||||
assert session1 is not session2
|
||||
|
||||
def test_create_session_ownership_transfers(self) -> None:
|
||||
"""Architecture spec: Ownership transfers to caller."""
|
||||
engine = FakeEngine()
|
||||
session = engine.createSession()
|
||||
assert isinstance(session, EngineSession)
|
||||
|
||||
|
||||
class TestEngineDisposeContract:
|
||||
"""Contract tests for Engine.dispose()."""
|
||||
|
||||
def test_dispose_is_idempotent(self) -> None:
|
||||
"""Architecture spec: dispose() is idempotent."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
engine.dispose() # Should not raise
|
||||
|
||||
def test_dispose_never_raises(self) -> None:
|
||||
"""Architecture spec: dispose() never raises exceptions."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose() # Should not raise
|
||||
|
||||
def test_create_session_after_dispose_raises(self) -> None:
|
||||
"""Architecture spec: After dispose(), all methods except dispose() raise EngineError."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
with pytest.raises(EngineError):
|
||||
engine.createSession()
|
||||
|
||||
|
||||
class TestEngineLifecycleContract:
|
||||
"""Contract tests for Engine lifecycle."""
|
||||
|
||||
def test_full_lifecycle(self) -> None:
|
||||
"""Test complete engine lifecycle: create -> sessions -> dispose."""
|
||||
engine = FakeEngine()
|
||||
|
||||
# Create sessions
|
||||
session1 = engine.createSession()
|
||||
session2 = engine.createSession()
|
||||
|
||||
# Use sessions
|
||||
assert isinstance(session1, EngineSession)
|
||||
assert isinstance(session2, EngineSession)
|
||||
|
||||
# Dispose sessions
|
||||
session1.dispose()
|
||||
session2.dispose()
|
||||
|
||||
# Dispose engine
|
||||
engine.dispose()
|
||||
|
||||
def test_engine_disposed_session_raises(self) -> None:
|
||||
"""Architecture spec: After dispose(), all methods except dispose() raise EngineError."""
|
||||
engine = FakeEngine()
|
||||
engine.dispose()
|
||||
with pytest.raises(EngineError):
|
||||
engine.createSession()
|
||||
|
||||
Reference in New Issue
Block a user