From 582e8de9daaebb7a00b600680191597c903ef7b9 Mon Sep 17 00:00:00 2001 From: linearcombination <4829djaskdfj@gmail.com> Date: Tue, 18 Aug 2026 19:21:03 -0700 Subject: [PATCH] Add unit tests for parsing function and update doctest --- backend/doc/domain/parsing.py | 67 ++++++++++++---- tests/unit/test_parsing.py | 140 ++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 15 deletions(-) diff --git a/backend/doc/domain/parsing.py b/backend/doc/domain/parsing.py index 10026d50..08c0c255 100644 --- a/backend/doc/domain/parsing.py +++ b/backend/doc/domain/parsing.py @@ -1453,26 +1453,61 @@ def split_chapter_into_verses_with_formatting( >>> html_content = ''' ... - ... 19 - ... For through the law I died to the law, so that I might live for God. I have been crucified with Christ. - ... 1 - ...
+ ... 1 + ... Généalogie + ... + ... de + ... Jésus + ... - + ... Christ + ... , + ... fils + ... de + ... David + ... , + ... fils + ... d' + ... Abraham + ... . + ... ...
... - ... 20 - ... I have been crucified with Christ and I no longer live, but Christ lives in me. The life I now live in the body, I live by faith in the Son of God, who loved me and gave himself for me. - ... 2 - ...
+ ... 2 + ... Abraham + ... + ... engendra + ... + ... Isaac + ... ; + ... + ... + ... Isaac + ... + ... engendra + ... + ... Jacob + ... ; + ... + ... + ... Jacob + ... + ... engendra + ... + ... Juda + ... + ... et + ... + ... ses + ... + ... frères + ... ; ...
... ''' >>> from doc.domain.parsing import split_chapter_into_verses_with_formatting >>> chapter = USFMChapter(content=html_content, verses=None) >>> chapter.verses = split_chapter_into_verses_with_formatting(chapter) - >>> print(chapter.verses["19"]) - 19 - For through the law I died to the law, so that I might live for God. I have been crucified with Christ. - 1 - + >>> print(chapter.verses["1"]) + Généalogie de Jésus-Christ, fils de David, fils d'Abraham. """ soup = BeautifulSoup(chapter.content, "html.parser") verse_dict: dict[VerseRef, str] = {} @@ -1505,9 +1540,11 @@ def clean_content_html(raw_content: str) -> str: if __name__ == "__main__": # To run the doctests in this module, in the root of the project do: - # python backend/document/domain/resource_lookup.py + # PYTHONPATH=backend python backend/doc/domain/parsing.py # or - # python backend/document/domain/resource_lookup.py -v + # PYTHONPATH=backend python backend/doc/domain/parsing.py -v + # These doctests are not collected by pytest: pyproject.toml sets + # testpaths = ["tests"] with no doctest collection, so run them by hand. # See https://docs.python.org/3/library/doctest.html # for more details. import doctest diff --git a/tests/unit/test_parsing.py b/tests/unit/test_parsing.py index c3188321..39644fcd 100644 --- a/tests/unit/test_parsing.py +++ b/tests/unit/test_parsing.py @@ -5,8 +5,10 @@ ensure_chapter_label, ensure_chapter_marker, maybe_localized_book_name, + split_chapter_into_verses_with_formatting, ) from doc.domain import model, resource_lookup +from doc.domain.model import USFMChapter def test_ensure_chapter_marker_unchanged_if_exists() -> None: @@ -102,5 +104,143 @@ def test_fr_f10_book_name_lookup_prefs() -> None: assert localized_book_name == expected +# Sample content taken from fr f10 Matthew 1, which uses word-entry tags. +FRENCH_WORD_ENTRY_HTML = """ + +1 + Généalogie + + de + Jésus +- + Christ +, + fils + de + David +, + fils + d' + Abraham +. + + + +2 + Abraham + + engendra + + Isaac +; + +""" + +# Sample content in the shape produced for USFM without word-entry tags: a +# footnote caller sup and a trailing sectionhead div follow the verse text. +GALATIANS_HTML = """ + + 19 +For through the law I died to the law, so that I might live for God. +1 +
+
+ +20 +I have been crucified with Christ and I no longer live. +2 +
+
+""" + + +def test_split_chapter_into_verses_with_formatting_keys() -> None: + chapter = USFMChapter(content=GALATIANS_HTML, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + assert list(verses.keys()) == ["19", "20"] + + +def test_split_chapter_into_verses_with_formatting_strips_verse_number_whitespace() -> ( + None +): + # The versemarker sup for verse 19 is written as " 19 ". + chapter = USFMChapter(content=GALATIANS_HTML, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + assert "19" in verses + assert " 19 " not in verses + + +def test_split_chapter_into_verses_with_formatting_removes_versemarker_only() -> None: + chapter = USFMChapter(content=GALATIANS_HTML, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + for verse in verses.values(): + assert "versemarker" not in verse + # Other markup inside the verse span survives. + assert verses["19"] == ( + ' For through the law I died to the law, ' + "so that I might live for God.\n" + '' + '1\n' + '
\n
' + ) + + +def test_split_chapter_into_verses_with_formatting_unwraps_word_entries() -> None: + chapter = USFMChapter(content=FRENCH_WORD_ENTRY_HTML, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + assert list(verses.keys()) == ["1", "2"] + for verse in verses.values(): + assert "word-entry" not in verse + # The wrapped text survives in place, with whitespace collapsed and + # whitespace before punctuation removed. + assert verses["1"] == ( + ' Généalogie de Jésus-Christ, fils de David, ' + "fils d'Abraham. " + ) + assert verses["2"] == ' Abraham engendra Isaac;\n' + + +def test_split_chapter_into_verses_with_formatting_collapses_hyphen_spacing() -> None: + """Spacing around a hyphen is intentionally collapsed (see clean_content_html).""" + chapter = USFMChapter(content=FRENCH_WORD_ENTRY_HTML, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + assert "Jésus-Christ" in verses["1"] + assert "Jésus - Christ" not in verses["1"] + + +def test_split_chapter_into_verses_with_formatting_skips_verses_without_versemarker() -> ( + None +): + html_content = """ + +No versemarker sup at all here. + + + +An empty versemarker sup here. + + +3 +A well formed verse. + +""" + chapter = USFMChapter(content=html_content, verses=None) + verses = split_chapter_into_verses_with_formatting(chapter) + assert list(verses.keys()) == ["3"] + assert verses["3"] == ' A well formed verse.\n' + + +def test_split_chapter_into_verses_with_formatting_without_verse_spans() -> None: + chapter = USFMChapter( + content="

Chapter content with no verse spans.

", verses=None + ) + assert split_chapter_into_verses_with_formatting(chapter) == {} + + +def test_split_chapter_into_verses_with_formatting_empty_content() -> None: + chapter = USFMChapter(content="", verses=None) + assert split_chapter_into_verses_with_formatting(chapter) == {} + + if __name__ == "__main__": pytest.main()