diff --git a/aeneas/tests/base_ttswrapper.py b/aeneas/tests/base_ttswrapper.py
index e72972a..a286a4f 100644
--- a/aeneas/tests/base_ttswrapper.py
+++ b/aeneas/tests/base_ttswrapper.py
@@ -25,14 +25,26 @@
import tempfile
import contextlib
import typing
-import itertools
+from aeneas.exacttiming import TimeValue
from aeneas.textfile import TextFile, TextFragment
from aeneas.ttswrappers.basettswrapper import BaseTTSWrapper
from aeneas.runtimeconfiguration import RuntimeConfiguration
+class SynthesizeCase(typing.NamedTuple):
+ c_ext: bool
+ cew_subprocess: bool
+ cache: bool
+
+
class TestBaseTTSWrapper(unittest.TestCase):
+ def test_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ BaseTTSWrapper()
+
+
+class BaseTTSWrapperCase(unittest.TestCase):
TTS = ""
TTS_PATH = ""
@@ -43,20 +55,20 @@ class TestBaseTTSWrapper(unittest.TestCase):
def synthesize(
self,
text_file,
- ofp=None,
- quit_after=None,
- backwards=False,
- zero_length=False,
+ ofp: str | None = None,
+ quit_after: TimeValue | None = None,
+ backwards: bool = False,
+ zero_length: bool = False,
expected_exc=None,
):
- if (
- (self.TTS == "")
- or (self.TTS_PATH == "")
- or (not os.path.exists(self.TTS_PATH))
- ):
- return
-
- def inner(c_ext, cew_subprocess, cache):
+ if not self.TTS:
+ self.skipTest("`self.TTS` is not set")
+ elif not self.TTS_PATH:
+ self.skipTest("`self.TTS_PATH` is not set")
+ elif not os.path.isfile(self.TTS_PATH):
+ self.skipTest(f"`self.TTS_PATH` ({self.TTS_PATH}) does not exist")
+
+ def inner(case: SynthesizeCase):
with contextlib.ExitStack() as exit_stack:
if ofp is None:
tmp_file = tempfile.NamedTemporaryFile(suffix=".wav")
@@ -69,36 +81,36 @@ def inner(c_ext, cew_subprocess, cache):
rconf = RuntimeConfiguration()
rconf[RuntimeConfiguration.TTS] = self.TTS
rconf[RuntimeConfiguration.TTS_PATH] = self.TTS_PATH
- rconf[RuntimeConfiguration.C_EXTENSIONS] = c_ext
- rconf[RuntimeConfiguration.CEW_SUBPROCESS_ENABLED] = cew_subprocess
- rconf[RuntimeConfiguration.TTS_CACHE] = cache
+ rconf[RuntimeConfiguration.C_EXTENSIONS] = case.c_ext
+ rconf[RuntimeConfiguration.CEW_SUBPROCESS_ENABLED] = (
+ case.cew_subprocess
+ )
+ rconf[RuntimeConfiguration.TTS_CACHE] = case.cache
tts_engine = self.TTS_CLASS(rconf=rconf)
anchors, total_time, num_chars = tts_engine.synthesize_multiple(
text_file, output_file_path, quit_after, backwards
)
- if cache:
+ if case.cache:
tts_engine.clear_cache()
+
if zero_length:
self.assertEqual(total_time, 0.0)
else:
self.assertGreater(total_time, 0.0)
+
except (OSError, TypeError, UnicodeDecodeError, ValueError) as exc:
- if cache and tts_engine is not None:
+ if case.cache and tts_engine is not None:
tts_engine.clear_cache()
with self.assertRaises(expected_exc):
raise exc
- if self.TTS == "espeak":
- for c_ext, cew_subprocess, cache in itertools.product(
- [True, False], repeat=3
- ):
- inner(c_ext=c_ext, cew_subprocess=cew_subprocess, cache=cache)
- elif self.TTS == "festival":
- for c_ext, cache in itertools.product([True, False], repeat=2):
- inner(c_ext=c_ext, cew_subprocess=False, cache=cache)
- else:
- for cache in [True, False]:
- inner(c_ext=True, cew_subprocess=False, cache=cache)
+ for case in self.iter_synthesize_cases():
+ with self.subTest(case=case):
+ inner(case)
+
+ def iter_synthesize_cases(self) -> typing.Iterator[SynthesizeCase]:
+ yield SynthesizeCase(c_ext=True, cew_subprocess=False, cache=True)
+ yield SynthesizeCase(c_ext=True, cew_subprocess=False, cache=False)
def tfl(self, frags):
tfl = TextFile()
@@ -108,10 +120,6 @@ def tfl(self, frags):
)
return tfl
- def test_not_implemented(self):
- with self.assertRaises(NotImplementedError):
- BaseTTSWrapper()
-
def test_use_cache(self):
if self.TTS == "":
self.skipTest("`self.TTS` is not set")
diff --git a/aeneas/tests/test_espeakngttswrapper.py b/aeneas/tests/test_espeakngttswrapper.py
index c5fe9a1..1ad30a6 100644
--- a/aeneas/tests/test_espeakngttswrapper.py
+++ b/aeneas/tests/test_espeakngttswrapper.py
@@ -21,11 +21,11 @@
# along with this program. If not, see .
-from aeneas.tests.base_ttswrapper import TestBaseTTSWrapper
from aeneas.ttswrappers.espeakngttswrapper import ESPEAKNGTTSWrapper
+from aeneas.tests.base_ttswrapper import BaseTTSWrapperCase
-class TestESPEAKNGTTSWrapper(TestBaseTTSWrapper):
+class TestESPEAKNGTTSWrapper(BaseTTSWrapperCase):
TTS = "espeak-ng"
TTS_PATH = "/usr/bin/espeak-ng"
TTS_CLASS = ESPEAKNGTTSWrapper
diff --git a/aeneas/tests/test_espeakttswrapper.py b/aeneas/tests/test_espeakttswrapper.py
index 4178e0f..3da1340 100644
--- a/aeneas/tests/test_espeakttswrapper.py
+++ b/aeneas/tests/test_espeakttswrapper.py
@@ -20,18 +20,23 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import itertools
-from aeneas.tests.base_ttswrapper import TestBaseTTSWrapper
+from aeneas.tests.base_ttswrapper import BaseTTSWrapperCase, SynthesizeCase
from aeneas.ttswrappers.espeakttswrapper import ESPEAKTTSWrapper
-class TestESPEAKTTSWrapper(TestBaseTTSWrapper):
+class TestESPEAKTTSWrapper(BaseTTSWrapperCase):
TTS = "espeak"
TTS_PATH = "/usr/bin/espeak"
TTS_CLASS = ESPEAKTTSWrapper
TTS_LANGUAGE = ESPEAKTTSWrapper.ENG
TTS_LANGUAGE_VARIATION = ESPEAKTTSWrapper.ENG_GBR
+ def iter_synthesize_cases(self):
+ for v in itertools.product([True, False], repeat=3):
+ yield SynthesizeCase(*v)
+
def test_multiple_replace_language(self):
tfl = self.tfl(
[(ESPEAKTTSWrapper.UKR, ["Временами Сашке хотелось перестать делать то"])]
diff --git a/aeneas/tests/test_festivalttswrapper.py b/aeneas/tests/test_festivalttswrapper.py
index b0074b9..896517e 100644
--- a/aeneas/tests/test_festivalttswrapper.py
+++ b/aeneas/tests/test_festivalttswrapper.py
@@ -20,14 +20,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import itertools
-from aeneas.tests.base_ttswrapper import TestBaseTTSWrapper
+from aeneas.tests.base_ttswrapper import BaseTTSWrapperCase, SynthesizeCase
from aeneas.ttswrappers.festivalttswrapper import FESTIVALTTSWrapper
-class TestFESTIVALTTSWrapper(TestBaseTTSWrapper):
+class TestFESTIVALTTSWrapper(BaseTTSWrapperCase):
TTS = "festival"
TTS_PATH = "/usr/bin/text2wave"
TTS_CLASS = FESTIVALTTSWrapper
TTS_LANGUAGE = FESTIVALTTSWrapper.ENG
TTS_LANGUAGE_VARIATION = FESTIVALTTSWrapper.ENG_GBR
+
+ def iter_synthesize_cases(self):
+ for c_ext, cache in itertools.product([True, False], repeat=2):
+ yield SynthesizeCase(c_ext=c_ext, cew_subprocess=False, cache=cache)
diff --git a/aeneas/tests/test_macosttswrapper.py b/aeneas/tests/test_macosttswrapper.py
index 69b2f54..dca6414 100644
--- a/aeneas/tests/test_macosttswrapper.py
+++ b/aeneas/tests/test_macosttswrapper.py
@@ -21,11 +21,11 @@
# along with this program. If not, see .
-from aeneas.tests.base_ttswrapper import TestBaseTTSWrapper
+from aeneas.tests.base_ttswrapper import BaseTTSWrapperCase
from aeneas.ttswrappers.macosttswrapper import MacOSTTSWrapper
-class TestESPEAKNGTTSWrapper(TestBaseTTSWrapper):
+class TestMacOSTTSWrapper(BaseTTSWrapperCase):
TTS = "macos"
TTS_PATH = "/usr/bin/say"
TTS_CLASS = MacOSTTSWrapper