221 lines
8.7 KiB
Python
221 lines
8.7 KiB
Python
import sys
|
|
import types
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
from types import SimpleNamespace
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
|
|
sound_stub = types.ModuleType("cthulhu.sound")
|
|
sound_stub.getPlayer = mock.Mock(return_value=None)
|
|
sys.modules.setdefault("cthulhu.sound", sound_stub)
|
|
|
|
speech_stub = types.ModuleType("cthulhu.speech")
|
|
speech_stub.speak = mock.Mock()
|
|
sys.modules.setdefault("cthulhu.speech", speech_stub)
|
|
|
|
from cthulhu import settings
|
|
from cthulhu.sound_generator import SoundGenerator
|
|
from cthulhu.sound_theme_manager import SoundThemeManager
|
|
from cthulhu.speech_generator import SpeechGenerator
|
|
from cthulhu.script_utilities import Utilities
|
|
|
|
|
|
class LinkSoundThemeRegressionTests(unittest.TestCase):
|
|
def test_default_theme_install_manifest_includes_link_sounds(self):
|
|
mesonPath = Path(__file__).resolve().parents[1] / "sounds" / "meson.build"
|
|
mesonText = mesonPath.read_text(encoding="utf-8")
|
|
|
|
self.assertIn("'default/link.wav'", mesonText)
|
|
self.assertIn("'default/link_visited.wav'", mesonText)
|
|
|
|
def _create_manager(self):
|
|
app = mock.Mock()
|
|
settingsManager = mock.Mock()
|
|
settingsManager.getSetting.return_value = "default"
|
|
app.getSettingsManager.return_value = settingsManager
|
|
return SoundThemeManager(app)
|
|
|
|
def test_visited_link_prefers_visited_asset(self):
|
|
manager = self._create_manager()
|
|
|
|
with mock.patch.object(
|
|
manager,
|
|
"getSoundPath",
|
|
side_effect=["/tmp/link_visited.wav", "/tmp/link.wav"],
|
|
):
|
|
icon = manager.getLinkSoundIcon(visited=True)
|
|
|
|
self.assertTrue(icon.path.endswith("link_visited.wav"))
|
|
|
|
def test_visited_link_falls_back_to_plain_link_asset(self):
|
|
manager = self._create_manager()
|
|
|
|
with mock.patch.object(
|
|
manager,
|
|
"getSoundPath",
|
|
side_effect=[None, "/tmp/link.wav"],
|
|
):
|
|
icon = manager.getLinkSoundIcon(visited=True)
|
|
|
|
self.assertTrue(icon.path.endswith("link.wav"))
|
|
|
|
|
|
class SpeechGeneratorLinkSoundRegressionTests(unittest.TestCase):
|
|
def test_role_sound_icon_uses_visited_link_asset_for_visited_links(self):
|
|
generator = object.__new__(SpeechGenerator)
|
|
generator._script = mock.Mock()
|
|
generator._script.utilities = mock.Mock()
|
|
|
|
icon = SimpleNamespace(path="/tmp/link_visited.wav")
|
|
|
|
with (
|
|
mock.patch("cthulhu.speech_generator.AXUtilities.is_link", return_value=True),
|
|
mock.patch("cthulhu.speech_generator.AXUtilities.is_visited", return_value=True),
|
|
mock.patch("cthulhu.speech_generator.sound_theme_manager.getManager") as get_manager,
|
|
):
|
|
get_manager.return_value.getLinkSoundIcon.return_value = icon
|
|
result = generator._getRoleSoundIcon(mock.Mock(), "link-role")
|
|
|
|
self.assertEqual(result, icon)
|
|
get_manager.return_value.getLinkSoundIcon.assert_called_once_with(visited=True)
|
|
|
|
|
|
class LinkIndicatorPresentationRegressionTests(unittest.TestCase):
|
|
def test_sound_only_inline_link_marker_uses_icon_instead_of_word(self):
|
|
utility = object.__new__(Utilities)
|
|
utility.adjustForLinks = mock.Mock(return_value="Docs link")
|
|
|
|
icon = SimpleNamespace(path="/tmp/link.wav")
|
|
link = mock.Mock()
|
|
|
|
def get_setting(name):
|
|
values = {
|
|
"roleSoundPresentation": settings.ROLE_SOUND_PRESENTATION_SOUND_ONLY,
|
|
"enableSound": True,
|
|
}
|
|
return values.get(name)
|
|
|
|
fakeApp = mock.Mock()
|
|
fakeApp.settingsManager.getSetting.side_effect = get_setting
|
|
|
|
with (
|
|
mock.patch("cthulhu.script_utilities.AXObject.supports_hypertext", return_value=True),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_all_links", return_value=[link]),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_link_start_offset", return_value=0),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_link_end_offset", return_value=4),
|
|
mock.patch("cthulhu.script_utilities.AXUtilities.is_visited", return_value=False),
|
|
mock.patch("cthulhu.sound_theme_manager.getManager") as get_manager,
|
|
mock.patch("cthulhu.script_utilities.cthulhu.cthulhuApp", fakeApp),
|
|
):
|
|
get_manager.return_value.getLinkSoundIcon.return_value = icon
|
|
spoken, icons = utility.getLinkIndicatorPresentation(mock.Mock(), "Docs", 0)
|
|
|
|
self.assertEqual(spoken, "Docs")
|
|
self.assertEqual(icons, [icon])
|
|
|
|
def test_sound_and_speech_inline_link_marker_keeps_word_and_adds_icon(self):
|
|
utility = object.__new__(Utilities)
|
|
utility.adjustForLinks = mock.Mock(return_value="Docs link")
|
|
|
|
icon = SimpleNamespace(path="/tmp/link_visited.wav")
|
|
link = mock.Mock()
|
|
|
|
def get_setting(name):
|
|
values = {
|
|
"roleSoundPresentation": settings.ROLE_SOUND_PRESENTATION_SOUND_AND_SPEECH,
|
|
"enableSound": True,
|
|
}
|
|
return values.get(name)
|
|
|
|
fakeApp = mock.Mock()
|
|
fakeApp.settingsManager.getSetting.side_effect = get_setting
|
|
|
|
with (
|
|
mock.patch("cthulhu.script_utilities.AXObject.supports_hypertext", return_value=True),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_all_links", return_value=[link]),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_link_start_offset", return_value=0),
|
|
mock.patch("cthulhu.script_utilities.AXHypertext.get_link_end_offset", return_value=4),
|
|
mock.patch("cthulhu.script_utilities.AXUtilities.is_visited", return_value=True),
|
|
mock.patch("cthulhu.sound_theme_manager.getManager") as get_manager,
|
|
mock.patch("cthulhu.script_utilities.cthulhu.cthulhuApp", fakeApp),
|
|
):
|
|
get_manager.return_value.getLinkSoundIcon.return_value = icon
|
|
spoken, icons = utility.getLinkIndicatorPresentation(mock.Mock(), "Docs", 0)
|
|
|
|
self.assertEqual(spoken, "Docs link")
|
|
self.assertEqual(icons, [icon])
|
|
|
|
def test_sound_pan_uses_object_position_inside_active_frame(self):
|
|
utility = object.__new__(Utilities)
|
|
obj = mock.Mock()
|
|
frame = mock.Mock()
|
|
icon = SimpleNamespace(path="/tmp/link.wav")
|
|
|
|
fakeApp = mock.Mock()
|
|
fakeApp.settingsManager.getSetting.return_value = True
|
|
|
|
def get_rect(target):
|
|
if target is frame:
|
|
return SimpleNamespace(x=0, y=0, width=1000, height=800)
|
|
if target is obj:
|
|
return SimpleNamespace(x=495, y=0, width=10, height=20)
|
|
return SimpleNamespace(x=0, y=0, width=0, height=0)
|
|
|
|
utility.frameAndDialog = mock.Mock(return_value=[frame, None])
|
|
|
|
with (
|
|
mock.patch("cthulhu.script_utilities.cthulhu.cthulhuApp", fakeApp),
|
|
mock.patch("cthulhu.script_utilities.AXComponent.get_rect", side_effect=get_rect),
|
|
):
|
|
utility.spatializeSoundIcon(icon, obj)
|
|
|
|
self.assertEqual(icon.pan, 0.0)
|
|
|
|
def test_sound_pan_hard_pans_only_at_extreme_edges(self):
|
|
utility = object.__new__(Utilities)
|
|
obj = mock.Mock()
|
|
frame = mock.Mock()
|
|
fakeApp = mock.Mock()
|
|
fakeApp.settingsManager.getSetting.return_value = True
|
|
|
|
utility.frameAndDialog = mock.Mock(return_value=[frame, None])
|
|
|
|
with (
|
|
mock.patch("cthulhu.script_utilities.cthulhu.cthulhuApp", fakeApp),
|
|
mock.patch(
|
|
"cthulhu.script_utilities.AXComponent.get_rect",
|
|
side_effect=[
|
|
SimpleNamespace(x=0, y=0, width=10, height=20),
|
|
SimpleNamespace(x=0, y=0, width=1000, height=800),
|
|
],
|
|
),
|
|
):
|
|
self.assertEqual(utility.getSoundPanForObject(obj), -1.0)
|
|
|
|
|
|
class SoundGeneratorSpatializationRegressionTests(unittest.TestCase):
|
|
def test_generated_icons_and_tones_are_spatialized(self):
|
|
generator = object.__new__(SoundGenerator)
|
|
icon = SimpleNamespace(path="/tmp/link.wav")
|
|
tone = SimpleNamespace(duration=0.1, frequency=440, volume=0.5, wave=0)
|
|
generator._script = mock.Mock()
|
|
generator._script.utilities.spatializeSoundIcon.side_effect = lambda sound, obj: sound
|
|
|
|
fakeApp = mock.Mock()
|
|
fakeApp.settingsManager.getSetting.return_value = True
|
|
obj = mock.Mock()
|
|
|
|
with mock.patch("cthulhu.sound_generator.cthulhu.cthulhuApp", fakeApp):
|
|
result = generator._spatializeSounds([icon, [tone]], obj)
|
|
|
|
self.assertEqual(result, [icon, [tone]])
|
|
generator._script.utilities.spatializeSoundIcon.assert_has_calls(
|
|
[mock.call(icon, obj), mock.call(tone, obj)]
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|