From dd2c98d4e0d8ab25dcf33e700742291d0f2ad784 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 7 Jun 2025 17:43:21 +0200 Subject: [PATCH] tests for word --- tests/test_abstract_inline.py | 204 ++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/tests/test_abstract_inline.py b/tests/test_abstract_inline.py index 2489e32..d913774 100644 --- a/tests/test_abstract_inline.py +++ b/tests/test_abstract_inline.py @@ -395,6 +395,210 @@ class TestWord(unittest.TestCase): Word.create_and_add_to("test", container) self.assertIn("must have an 'add_word' method", str(context.exception)) + + def test_word_create_and_add_to_parameter_inspection_word_object(self): + """Test Word.create_and_add_to with add_word method that expects Word object.""" + # Create container with add_word method that has 'word' parameter name + class WordObjectContainer: + def __init__(self, font): + self.style = font + self.added_words = [] + + def add_word(self, word): # Parameter named 'word' indicates it expects Word object + self.added_words.append(word) + + container = WordObjectContainer(self.font) + + # Create and add word + word = Word.create_and_add_to("test", container) + + # Test that the Word object was passed to add_word + self.assertEqual(len(container.added_words), 1) + self.assertEqual(container.added_words[0], word) + self.assertIsInstance(container.added_words[0], Word) + + def test_word_create_and_add_to_parameter_inspection_word_obj(self): + """Test Word.create_and_add_to with add_word method that has 'word_obj' parameter.""" + class WordObjContainer: + def __init__(self, font): + self.style = font + self.added_words = [] + + def add_word(self, word_obj): # Parameter named 'word_obj' indicates it expects Word object + self.added_words.append(word_obj) + + container = WordObjContainer(self.font) + word = Word.create_and_add_to("test", container) + + self.assertEqual(len(container.added_words), 1) + self.assertEqual(container.added_words[0], word) + + def test_word_create_and_add_to_parameter_inspection_word_object(self): + """Test Word.create_and_add_to with add_word method that has 'word_object' parameter.""" + class WordObjectContainer: + def __init__(self, font): + self.style = font + self.added_words = [] + + def add_word(self, word_object): # Parameter named 'word_object' indicates it expects Word object + self.added_words.append(word_object) + + container = WordObjectContainer(self.font) + word = Word.create_and_add_to("test", container) + + self.assertEqual(len(container.added_words), 1) + self.assertEqual(container.added_words[0], word) + + def test_word_create_and_add_to_parameter_inspection_text_fallback_with_words_list(self): + """Test Word.create_and_add_to with add_word that expects text but container has _words list.""" + class TextExpectingContainer: + def __init__(self, font): + self.style = font + self._words = [] # Has _words list + self.add_word_calls = [] + + def add_word(self, text): # Parameter named 'text' suggests it expects string + # This simulates FormattedSpan.add_word behavior + self.add_word_calls.append(text) + # In real FormattedSpan, this would create a Word internally + + container = TextExpectingContainer(self.font) + word = Word.create_and_add_to("test", container) + + # Word should be added to _words list directly, not via add_word + self.assertEqual(len(container._words), 1) + self.assertEqual(container._words[0], word) + # add_word should not have been called since it expects text + self.assertEqual(len(container.add_word_calls), 0) + + def test_word_create_and_add_to_parameter_inspection_fallback_without_words_list(self): + """Test Word.create_and_add_to fallback when container doesn't have _words list.""" + class TextExpectingContainer: + def __init__(self, font): + self.style = font + # No _words list + self.added_words = [] + + def add_word(self, text): # Parameter suggests text but we'll pass Word as fallback + self.added_words.append(text) + + container = TextExpectingContainer(self.font) + word = Word.create_and_add_to("test", container) + + # Should fallback to calling add_word with Word object + self.assertEqual(len(container.added_words), 1) + self.assertEqual(container.added_words[0], word) + + def test_word_create_and_add_to_no_parameters_edge_case(self): + """Test Word.create_and_add_to with add_word method that has no parameters.""" + class NoParamsContainer: + def __init__(self, font): + self.style = font + self.add_word_called = False + + def add_word(self): # No parameters - edge case + self.add_word_called = True + + container = NoParamsContainer(self.font) + + # The current implementation will fail when calling add_word(word) with a no-parameter method + with self.assertRaises(TypeError) as context: + Word.create_and_add_to("test", container) + + self.assertIn("takes 1 positional argument but 2 were given", str(context.exception)) + + def test_word_create_and_add_to_linking_behavior_with_existing_words(self): + """Test Word.create_and_add_to properly links with existing words in container.""" + # Create container with existing words + class ContainerWithWords: + def __init__(self, font): + self.style = font + self._words = [] + # Add an existing word + existing_word = Word("existing", font) + self._words.append(existing_word) + + def add_word(self, word): + self._words.append(word) + + container = ContainerWithWords(self.font) + existing_word = container._words[0] + + # Create new word + new_word = Word.create_and_add_to("new", container) + + # Test linking + self.assertEqual(new_word.previous, existing_word) + self.assertEqual(existing_word.next, new_word) + self.assertEqual(len(container._words), 2) + self.assertEqual(container._words[1], new_word) + + def test_word_create_and_add_to_linking_behavior_with_words_method(self): + """Test Word.create_and_add_to properly links with words from container.words() method.""" + class ContainerWithWordsMethod: + def __init__(self, font): + self.style = font + self.existing_word1 = Word("first", font) + self.existing_word2 = Word("second", font) + self.existing_word1.add_next(self.existing_word2) + self.added_words = [] + + def words(self): + yield ("span1", self.existing_word1) + yield ("span2", self.existing_word2) + + def add_word(self, word): + self.added_words.append(word) + + container = ContainerWithWordsMethod(self.font) + + # Create new word + new_word = Word.create_and_add_to("third", container) + + # Should link to the last word returned by words() method + self.assertEqual(new_word.previous, container.existing_word2) + self.assertEqual(container.existing_word2.next, new_word) + + def test_word_create_and_add_to_linking_behavior_empty_words_method(self): + """Test Word.create_and_add_to with empty words() method.""" + class EmptyWordsContainer: + def __init__(self, font): + self.style = font + + def words(self): + # Empty iterator + return iter([]) + + def add_word(self, word): + pass + + container = EmptyWordsContainer(self.font) + + # Create word + word = Word.create_and_add_to("test", container) + + # Should have no previous word + self.assertIsNone(word.previous) + + def test_word_create_and_add_to_linking_behavior_words_method_exception(self): + """Test Word.create_and_add_to with words() method that raises exception.""" + class ExceptionWordsContainer: + def __init__(self, font): + self.style = font + + def words(self): + raise TypeError("Error in words method") + + def add_word(self, word): + pass + + container = ExceptionWordsContainer(self.font) + + # Create word - should handle exception gracefully + word = Word.create_and_add_to("test", container) + + # Should have no previous word due to exception + self.assertIsNone(word.previous) class TestFormattedSpan(unittest.TestCase):