OPEN SOURCE
software/tests/test_coverage_gaps.py
Read on this site and download the files you need.
Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.
← Back to the open-source guide
1"""Tests to fill coverage gaps in various modules."""23import json4import pytest5from pathlib import Path6from tempfile import TemporaryDirectory78from src.context.cross_references import (9CrossReference,10CrossReferenceManager,11ReferenceType,12)13from src.context.glossary import GlossaryManager14from src.context.pericope_generator import PericopeGenerator15from src.models.glossary import EnhancedGlossaryTerm, TheologicalDomain16from src.utils.retry import RetryConfig, RetryState17from src.utils.validation import (18normalize_book_name,19parse_reference_string,20validate_chapter,21)22from src.exceptions import InvalidReferenceError, RateLimitError232425class TestGlossaryMorphologicalMatching:26"""Tests for morphological glossary matching."""2728def test_get_by_lemma(self) -> None:29"""Test getting terms by lemma."""30terms = [31EnhancedGlossaryTerm(32original="λόγος",33transliteration="logos",34japanese="言葉",35english="word",36lemma="λογος",37)38]39manager = GlossaryManager(terms)4041# Get by lemma42found = manager.get_by_lemma("λογος")43assert found is not None44assert found.original == "λόγος"4546def test_get_by_lemma_not_found(self) -> None:47"""Test getting by lemma returns None for unknown lemma."""48terms = [49EnhancedGlossaryTerm(50original="λόγος",51transliteration="logos",52japanese="言葉",53english="word",54)55]56manager = GlossaryManager(terms)5758found = manager.get_by_lemma("unknown")59assert found is None6061def test_get_by_strongs(self) -> None:62"""Test getting terms by Strong's number."""63terms = [64EnhancedGlossaryTerm(65original="λόγος",66transliteration="logos",67japanese="言葉",68english="word",69strongs_number="G3056",70)71]72manager = GlossaryManager(terms)7374found = manager.get_by_strongs("G3056")75assert found is not None76assert found.original == "λόγος"7778def test_get_by_strongs_case_insensitive(self) -> None:79"""Test Strong's lookup is case insensitive."""80terms = [81EnhancedGlossaryTerm(82original="λόγος",83transliteration="logos",84japanese="言葉",85english="word",86strongs_number="G3056",87)88]89manager = GlossaryManager(terms)9091# Lowercase should work too92found = manager.get_by_strongs("g3056")93assert found is not None94assert found.original == "λόγος"9596def test_get_by_strongs_not_found(self) -> None:97"""Test Strong's lookup returns None for unknown number."""98terms = [99EnhancedGlossaryTerm(100original="λόγος",101transliteration="logos",102japanese="言葉",103english="word",104)105]106manager = GlossaryManager(terms)107108found = manager.get_by_strongs("G9999")109assert found is None110111def test_find_terms_with_inflected_forms(self) -> None:112"""Test finding terms via inflected forms."""113terms = [114EnhancedGlossaryTerm(115original="λόγος",116transliteration="logos",117japanese="言葉",118english="word",119inflected_forms=["λόγον", "λόγου", "λόγῳ"],120)121]122manager = GlossaryManager(terms)123124# Text containing inflected form125text = "καὶ ὁ λόγον ἦν"126found = manager.find_terms_in_text(text)127assert len(found) == 1128assert found[0].original == "λόγος"129130def test_get_by_domain(self) -> None:131"""Test getting terms by theological domain."""132terms = [133EnhancedGlossaryTerm(134original="λόγος",135transliteration="logos",136japanese="言葉",137english="word",138domain=TheologicalDomain.CHRISTOLOGY,139),140EnhancedGlossaryTerm(141original="σωτηρία",142transliteration="soteria",143japanese="救い",144english="salvation",145domain=TheologicalDomain.SOTERIOLOGY,146),147]148manager = GlossaryManager(terms)149150christology = manager.get_by_domain(TheologicalDomain.CHRISTOLOGY)151assert len(christology) == 1152assert christology[0].original == "λόγος"153154soteriology = manager.get_by_domain(TheologicalDomain.SOTERIOLOGY)155assert len(soteriology) == 1156assert soteriology[0].original == "σωτηρία"157158def test_get_by_any_form(self) -> None:159"""Test getting terms by any matchable form."""160terms = [161EnhancedGlossaryTerm(162original="λόγος",163transliteration="logos",164japanese="言葉",165english="word",166lemma="λογος",167inflected_forms=["λόγον"],168)169]170manager = GlossaryManager(terms)171172# Should find by original173found = manager.get_by_any_form("λόγος")174assert found is not None175176# Should find by lemma177found = manager.get_by_any_form("λογος")178assert found is not None179180# Should find by inflected form181found = manager.get_by_any_form("λόγον")182assert found is not None183184185class TestCrossReferenceEdgeCases:186"""Tests for cross-reference edge cases."""187188def test_find_references_to_verse_exact_match(self) -> None:189"""Test finding references to exact verse (not range)."""190manager = CrossReferenceManager()191ref = CrossReference(192source_book="john",193source_chapter=1,194source_verse=1,195target_book="genesis",196target_chapter=1,197target_verse_start=1,198)199manager.add_reference(ref)200201# Should find reference TO verse 1202found = manager.find_references_to_verse("genesis", 1, 1)203assert len(found) == 1204205def test_get_consistency_notes_no_hint(self) -> None:206"""Test consistency notes when no translation hint."""207manager = CrossReferenceManager()208ref = CrossReference(209source_book="john",210source_chapter=1,211source_verse=23,212target_book="isaiah",213target_chapter=40,214target_verse_start=3,215reference_type=ReferenceType.QUOTATION,216# No translation_hint217)218manager.add_reference(ref)219220notes = manager.get_translation_consistency_notes("john", 1, 23)221# Should still have note about quotation222assert any("quotes" in n.lower() for n in notes)223224def test_format_for_prompt_with_max(self) -> None:225"""Test prompt formatting respects max_references."""226manager = CrossReferenceManager()227for i in range(10):228manager.add_reference(229CrossReference(230source_book="john",231source_chapter=1,232source_verse=1,233target_book="genesis",234target_chapter=1,235target_verse_start=i + 1,236)237)238239refs = manager.find_references_for_verse("john", 1, 1)240formatted = manager.format_for_prompt(refs, max_references=3)241242# Should only include 3243assert formatted.count("genesis") == 3244245246class TestPericopeGeneratorEdgeCases:247"""Tests for pericope generator edge cases."""248249def test_generate_pericopes_no_markers(self) -> None:250"""Test generating pericopes when no paragraph markers exist."""251with TemporaryDirectory() as tmpdir:252data_dir = Path(tmpdir)253greek_dir = data_dir / "sources" / "greek"254greek_dir.mkdir(parents=True)255256# Greek data without paragraph markers257greek_data = {258"1:1": {"text": "Ἐν ἀρχῇ ἦν ὁ λόγος"},259"1:2": {"text": "οὗτος ἦν ἐν ἀρχῇ"},260"1:3": {"text": "πάντα δι' αὐτοῦ ἐγένετο"},261}262with (greek_dir / "test.json").open("w") as f:263json.dump(greek_data, f)264265generator = PericopeGenerator(data_dir)266index = generator.generate_pericopes("test", min_size=1)267268# Should create one pericope covering all verses269assert len(index.pericopes) >= 1270271def test_ref_sort_key_complex(self) -> None:272"""Test reference sort key with various formats."""273with TemporaryDirectory() as tmpdir:274data_dir = Path(tmpdir)275(data_dir / "sources" / "greek").mkdir(parents=True)276277generator = PericopeGenerator(data_dir)278279# Standard refs280assert generator._ref_sort_key("10:25") == (10, 25)281assert generator._ref_sort_key("1:1") < generator._ref_sort_key("1:2")282assert generator._ref_sort_key("1:10") < generator._ref_sort_key("2:1")283284def test_split_large_pericope_exact_fit(self) -> None:285"""Test splitting when verses exactly fit max_size."""286with TemporaryDirectory() as tmpdir:287data_dir = Path(tmpdir)288(data_dir / "sources" / "greek").mkdir(parents=True)289290generator = PericopeGenerator(data_dir)291292# 10 verses with max_size=10 should not split293verses = [f"1:{i}" for i in range(1, 11)]294result = generator._split_large_pericope(verses, max_size=10)295assert len(result) == 1296assert result[0] == verses297298299class TestRetryEdgeCases:300"""Tests for retry utility edge cases."""301302def test_retry_state_with_rate_limit_retry_after(self) -> None:303"""Test retry state uses retry_after from rate limit error."""304config = RetryConfig(305base_delay=10.0,306jitter=False,307retryable_exceptions=(RateLimitError,),308)309state = RetryState(config)310311error = RateLimitError("Rate limit", retry_after=0.001)312state.should_retry(error)313314# Wait should use retry_after, not base_delay315import time316317start = time.time()318state.wait()319elapsed = time.time() - start320321# Should be very fast (using retry_after=0.001)322assert elapsed < 1.0323324def test_retry_config_jitter_bounds(self) -> None:325"""Test jitter stays within bounds."""326config = RetryConfig(base_delay=1.0, jitter=True)327328for _ in range(50):329delay = config.get_delay(0)330# Jitter should be +/- 25%331assert 0.75 <= delay <= 1.25332333334class TestValidationEdgeCases:335"""Tests for validation edge cases."""336337def test_parse_reference_numbered_book_variants(self) -> None:338"""Test parsing various numbered book formats."""339# Space between number and name340book, chapter, verse = parse_reference_string("1 John 1:1")341assert book == "1john"342assert chapter == 1343assert verse == 1344345# No space346book, chapter, verse = parse_reference_string("1John 1:1")347assert book == "1john"348349def test_normalize_book_with_spaces_and_hyphens(self) -> None:350"""Test normalizing book names with various separators."""351assert normalize_book_name("song of solomon") == "songofsolomon"352assert normalize_book_name("song-of-solomon") == "songofsolomon"353354def test_validate_chapter_known_books(self) -> None:355"""Test chapter validation for known books."""356# John has 21 chapters357validate_chapter("john", 21) # Should pass358359with pytest.raises(InvalidReferenceError):360validate_chapter("john", 22) # Should fail361362# Psalms has 150 chapters363validate_chapter("psalms", 150) # Should pass364365366class TestEnhancedGlossaryTerm:367"""Tests for enhanced glossary term model."""368369def test_get_all_matchable_forms_with_lemma(self) -> None:370"""Test getting all matchable forms."""371term = EnhancedGlossaryTerm(372original="λόγος",373transliteration="logos",374japanese="言葉",375english="word",376lemma="λογος",377inflected_forms=["λόγον", "λόγου"],378)379380forms = term.get_all_matchable_forms()381assert "λόγος" in forms382# Lemma should be included if different from original383assert "λογος" in forms384assert "λόγον" in forms385assert "λόγου" in forms386387def test_get_all_matchable_forms_minimal(self) -> None:388"""Test matchable forms with minimal data."""389term = EnhancedGlossaryTerm(390original="λόγος",391transliteration="logos",392japanese="言葉",393english="word",394)395396forms = term.get_all_matchable_forms()397assert "λόγος" in forms398# Transliteration is NOT included in get_all_matchable_forms399# Only original, lemma, and inflected forms400assert len(forms) == 1401402def test_get_all_matchable_forms_same_lemma(self) -> None:403"""Test that lemma is not duplicated if same as original."""404term = EnhancedGlossaryTerm(405original="λόγος",406transliteration="logos",407japanese="言葉",408english="word",409lemma="λόγος", # Same as original410)411412forms = term.get_all_matchable_forms()413# Should not duplicate the original414assert len(forms) == 1415assert forms[0] == "λόγος"416417418class TestCrossReferenceManagerSaveLoad:419"""Tests for cross-reference save/load functionality."""420421def test_save_and_load_with_all_fields(self) -> None:422"""Test saving and loading cross-references with all fields."""423with TemporaryDirectory() as tmpdir:424data_dir = Path(tmpdir)425metadata_dir = data_dir / "metadata"426metadata_dir.mkdir(parents=True)427428manager = CrossReferenceManager()429manager._data_dir = data_dir430431# Add reference with all optional fields432manager.add_reference(433CrossReference(434source_book="john",435source_chapter=1,436source_verse=1,437target_book="genesis",438target_chapter=1,439target_verse_start=1,440target_verse_end=3,441reference_type=ReferenceType.ALLUSION,442note="Echoes Genesis",443translation_hint="Use similar phrasing",444)445)446447manager.save()448449# Load into new manager450manager2 = CrossReferenceManager(data_dir)451assert len(manager2) == 1452453found = manager2.find_references_for_verse("john", 1, 1)454assert len(found) == 1455assert found[0].note == "Echoes Genesis"456assert found[0].translation_hint == "Use similar phrasing"457