Files
cthulhu/tests/test_pronunciation_dictionary_manager.py

279 lines
11 KiB
Python

# Unit tests for pronunciation_dictionary_manager.py.
#
# Copyright 2026 Igalia, S.L.
# Author: Joanmarie Diggs <jdiggs@igalia.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
# pylint: disable=wrong-import-position
# pylint: disable=protected-access
# pylint: disable=import-outside-toplevel
"""Unit tests for pronunciation_dictionary_manager.py."""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
if TYPE_CHECKING:
from cthulhu_test_context import CthulhuTestContext
@pytest.mark.unit
class TestPronunciationDictionaryManager:
"""Test PronunciationDictionaryManager class."""
def _setup_manager(self, test_context: CthulhuTestContext):
"""Set up mocks for pronunciation_dictionary_manager dependencies."""
additional_modules = [
"cthulhu.guilabels",
"cthulhu.messages",
"cthulhu.preferences_grid_base",
"cthulhu.script_manager",
"cthulhu.speech_manager",
]
essential_modules = test_context.setup_shared_dependencies(additional_modules)
# Set up guilabels with required constants
guilabels = essential_modules["cthulhu.guilabels"]
guilabels.PRONUNCIATION = "Pronunciation"
guilabels.PRONUNCIATION_DICTIONARY = "Pronunciation Dictionary"
guilabels.PRONUNCIATION_DICTIONARY_INFO = "Add custom pronunciations."
guilabels.DICTIONARY_NEW_ENTRY = "New Entry"
guilabels.DICTIONARY_DELETE = "Delete"
guilabels.DICTIONARY_EMPTY = "No entries"
guilabels.DICTIONARY_ACTUAL_STRING = "Actual String"
guilabels.DICTIONARY_REPLACEMENT_STRING = "Replacement String"
guilabels.ADD_NEW_PRONUNCIATION = "Add New Pronunciation"
guilabels.EDIT_PRONUNCIATION = "Edit Pronunciation"
guilabels.DIALOG_CANCEL = "Cancel"
guilabels.DIALOG_ADD = "Add"
guilabels.DIALOG_EDIT = "Edit"
# Set up messages
messages = essential_modules["cthulhu.messages"]
messages.PRONUNCIATION_DELETED = "Pronunciation %s deleted"
# Set up speech_manager
speech_manager_mock = essential_modules["cthulhu.speech_manager"]
speech_instance = speech_manager_mock.get_manager.return_value
speech_instance.get_use_pronunciation_dictionary.return_value = True
speech_instance.set_use_pronunciation_dictionary.return_value = True
# Import and return the module
from cthulhu import pronunciation_dictionary_manager
return pronunciation_dictionary_manager, essential_modules
def test_get_manager_returns_singleton(self, test_context: CthulhuTestContext) -> None:
"""Test get_manager returns the same instance."""
module, _mocks = self._setup_manager(test_context)
manager1 = module.get_manager()
manager2 = module.get_manager()
assert manager1 is manager2
def test_manager_initial_state(self, test_context: CthulhuTestContext) -> None:
"""Test manager initializes with empty dictionary."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
# Reset the dictionary to ensure clean state
manager.set_dictionary({})
assert manager.get_dictionary() == {}
def test_get_pronunciation_returns_word_when_not_found(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test get_pronunciation returns the original word when not in dictionary."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
result = manager.get_pronunciation("hello")
assert result == "hello"
def test_get_pronunciation_returns_replacement_when_found(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test get_pronunciation returns replacement when word is in dictionary."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("hello", "hi there")
result = manager.get_pronunciation("hello")
assert result == "hi there"
def test_get_pronunciation_is_case_insensitive(self, test_context: CthulhuTestContext) -> None:
"""Test get_pronunciation lookup is case insensitive."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("HELLO", "hi there")
assert manager.get_pronunciation("hello") == "hi there"
assert manager.get_pronunciation("Hello") == "hi there"
assert manager.get_pronunciation("HELLO") == "hi there"
def test_set_pronunciation_stores_lowercase_key(self, test_context: CthulhuTestContext) -> None:
"""Test set_pronunciation stores key as lowercase."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("MixedCase", "replacement")
dictionary = manager.get_dictionary()
assert "mixedcase" in dictionary
assert "MixedCase" not in dictionary
def test_set_dictionary_replaces_entire_dictionary(self, test_context: CthulhuTestContext) -> None:
"""Test set_dictionary replaces the entire dictionary."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_pronunciation("old", "old replacement")
manager.set_dictionary({"new": "new replacement"})
dictionary = manager.get_dictionary()
assert "old" not in dictionary
assert dictionary.get("new") == "new replacement"
def test_multiple_pronunciations(self, test_context: CthulhuTestContext) -> None:
"""Test manager handles multiple pronunciations correctly."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("word1", "replacement1")
manager.set_pronunciation("word2", "replacement2")
manager.set_pronunciation("word3", "replacement3")
assert manager.get_pronunciation("word1") == "replacement1"
assert manager.get_pronunciation("word2") == "replacement2"
assert manager.get_pronunciation("word3") == "replacement3"
assert len(manager.get_dictionary()) == 3
def test_set_pronunciation_overwrites_existing(self, test_context: CthulhuTestContext) -> None:
"""Test set_pronunciation overwrites existing entry for same word."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("word", "first replacement")
manager.set_pronunciation("word", "second replacement")
assert manager.get_pronunciation("word") == "second replacement"
assert len(manager.get_dictionary()) == 1
@pytest.mark.unit
class TestPronunciationDictionaryManagerIntegration:
"""Integration tests for pronunciation dictionary manager."""
def _setup_manager(self, test_context: CthulhuTestContext):
"""Set up mocks for pronunciation_dictionary_manager dependencies."""
additional_modules = [
"cthulhu.guilabels",
"cthulhu.messages",
"cthulhu.preferences_grid_base",
"cthulhu.script_manager",
"cthulhu.speech_manager",
]
essential_modules = test_context.setup_shared_dependencies(additional_modules)
# Set up guilabels with required constants
guilabels = essential_modules["cthulhu.guilabels"]
guilabels.PRONUNCIATION = "Pronunciation"
guilabels.PRONUNCIATION_DICTIONARY = "Pronunciation Dictionary"
guilabels.PRONUNCIATION_DICTIONARY_INFO = "Add custom pronunciations."
guilabels.DICTIONARY_NEW_ENTRY = "New Entry"
guilabels.DICTIONARY_DELETE = "Delete"
guilabels.DICTIONARY_EMPTY = "No entries"
guilabels.DICTIONARY_ACTUAL_STRING = "Actual String"
guilabels.DICTIONARY_REPLACEMENT_STRING = "Replacement String"
guilabels.ADD_NEW_PRONUNCIATION = "Add New Pronunciation"
guilabels.EDIT_PRONUNCIATION = "Edit Pronunciation"
guilabels.DIALOG_CANCEL = "Cancel"
guilabels.DIALOG_ADD = "Add"
guilabels.DIALOG_EDIT = "Edit"
# Set up messages
messages = essential_modules["cthulhu.messages"]
messages.PRONUNCIATION_DELETED = "Pronunciation %s deleted"
# Set up speech_manager
speech_manager_mock = essential_modules["cthulhu.speech_manager"]
speech_instance = speech_manager_mock.get_manager.return_value
speech_instance.get_use_pronunciation_dictionary.return_value = True
speech_instance.set_use_pronunciation_dictionary.return_value = True
# Import and return the module
from cthulhu import pronunciation_dictionary_manager
return pronunciation_dictionary_manager, essential_modules
def test_pronunciation_application_to_text(self, test_context: CthulhuTestContext) -> None:
"""Test that pronunciation dictionary can be used to process text."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
manager.set_pronunciation("github", "git hub")
manager.set_pronunciation("cli", "command line interface")
# Simulate applying pronunciations to a sentence
words = ["Check", " ", "out", " ", "the", " ", "GitHub", " ", "CLI"]
result = "".join(map(manager.get_pronunciation, words))
# GitHub becomes "git hub" because lookup is case insensitive
assert "git hub" in result
# CLI becomes "command line interface"
assert "command line interface" in result
def test_empty_dictionary_returns_original_words(self, test_context: CthulhuTestContext) -> None:
"""Test that empty dictionary returns all original words unchanged."""
module, _mocks = self._setup_manager(test_context)
manager = module.get_manager()
manager.set_dictionary({})
words = ["Hello", " ", "world", "!"]
result = "".join(map(manager.get_pronunciation, words))
assert result == "Hello world!"