"""Tests for cross-reference system.""" import json import pytest from pathlib import Path from tempfile import TemporaryDirectory from src.context.cross_references import ( CrossReference, CrossReferenceManager, CrossReferenceMatch, JOHN_CROSS_REFERENCES, ReferenceType, create_default_cross_references, ) class TestReferenceType: """Tests for ReferenceType enum.""" def test_all_types_exist(self): """Test all expected reference types exist.""" assert ReferenceType.QUOTATION.value == "quotation" assert ReferenceType.ALLUSION.value == "allusion" assert ReferenceType.PARALLEL.value == "parallel" assert ReferenceType.THEMATIC.value == "thematic" assert ReferenceType.FULFILLMENT.value == "fulfillment" assert ReferenceType.TYPOLOGY.value == "typology" class TestCrossReference: """Tests for CrossReference model.""" def test_basic_creation(self): """Test basic cross-reference creation.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) assert ref.source_book == "john" assert ref.target_book == "genesis" assert ref.reference_type == ReferenceType.THEMATIC def test_with_verse_range(self): """Test cross-reference with verse range.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=14, target_book="exodus", target_chapter=33, target_verse_start=7, target_verse_end=11, ) assert ref.target_verse_start == 7 assert ref.target_verse_end == 11 def test_with_note_and_hint(self): """Test cross-reference with note and translation hint.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, reference_type=ReferenceType.ALLUSION, note="John echoes Genesis opening", translation_hint="Use similar phrasing", ) assert ref.note == "John echoes Genesis opening" assert ref.translation_hint == "Use similar phrasing" assert ref.reference_type == ReferenceType.ALLUSION def test_source_ref_property(self): """Test source_ref property.""" ref = CrossReference( source_book="john", source_chapter=3, source_verse=16, target_book="genesis", target_chapter=1, target_verse_start=1, ) assert ref.source_ref == "john 3:16" def test_target_ref_property_single_verse(self): """Test target_ref property for single verse.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) assert ref.target_ref == "genesis 1:1" def test_target_ref_property_verse_range(self): """Test target_ref property for verse range.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=14, target_book="exodus", target_chapter=33, target_verse_start=7, target_verse_end=11, ) assert ref.target_ref == "exodus 33:7-11" class TestCrossReferenceMatch: """Tests for CrossReferenceMatch model.""" def test_basic_creation(self): """Test basic match creation.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) match = CrossReferenceMatch(reference=ref) assert match.reference == ref assert match.target_text is None assert match.target_translation is None assert match.relevance_score == 1.0 def test_with_context(self): """Test match with target text and translation.""" ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) match = CrossReferenceMatch( reference=ref, target_text="In the beginning God created...", target_translation="初めに神は天と地を創造された。", relevance_score=0.95, ) assert match.target_text is not None assert match.target_translation is not None assert match.relevance_score == 0.95 class TestCrossReferenceManager: """Tests for CrossReferenceManager.""" def test_empty_manager(self): """Test empty manager initialization.""" manager = CrossReferenceManager() assert len(manager) == 0 def test_add_reference(self): """Test adding a reference.""" manager = CrossReferenceManager() ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) manager.add_reference(ref) assert len(manager) == 1 def test_find_references_for_verse(self): """Test finding references for a verse.""" manager = CrossReferenceManager() ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) manager.add_reference(ref) found = manager.find_references_for_verse("john", 1, 1) assert len(found) == 1 assert found[0].target_book == "genesis" def test_find_references_for_verse_case_insensitive(self): """Test finding references is case insensitive.""" manager = CrossReferenceManager() ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) manager.add_reference(ref) found = manager.find_references_for_verse("John", 1, 1) assert len(found) == 1 def test_find_references_to_verse(self): """Test finding references TO a verse.""" manager = CrossReferenceManager() ref = CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, ) manager.add_reference(ref) found = manager.find_references_to_verse("genesis", 1, 1) assert len(found) == 1 assert found[0].source_book == "john" def test_find_references_by_type(self): """Test finding references by type.""" manager = CrossReferenceManager() manager.add_reference( CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, reference_type=ReferenceType.ALLUSION, ) ) manager.add_reference( CrossReference( source_book="john", source_chapter=1, source_verse=23, target_book="isaiah", target_chapter=40, target_verse_start=3, reference_type=ReferenceType.QUOTATION, ) ) allusions = manager.find_references_by_type("john", 1, 1, ReferenceType.ALLUSION) assert len(allusions) == 1 quotations = manager.find_references_by_type("john", 1, 23, ReferenceType.QUOTATION) assert len(quotations) == 1 def test_get_quotation_sources(self): """Test getting quotation sources.""" manager = CrossReferenceManager() manager.add_reference( CrossReference( source_book="john", source_chapter=1, source_verse=23, target_book="isaiah", target_chapter=40, target_verse_start=3, reference_type=ReferenceType.QUOTATION, ) ) quotes = manager.get_quotation_sources("john", 1, 23) assert len(quotes) == 1 assert quotes[0].target_book == "isaiah" def test_get_parallel_passages(self): """Test getting parallel passages.""" manager = CrossReferenceManager() manager.add_reference( CrossReference( source_book="matthew", source_chapter=3, source_verse=1, target_book="mark", target_chapter=1, target_verse_start=2, reference_type=ReferenceType.PARALLEL, ) ) parallels = manager.get_parallel_passages("matthew", 3, 1) assert len(parallels) == 1 assert parallels[0].target_book == "mark" def test_format_for_prompt_empty(self): """Test formatting empty references.""" manager = CrossReferenceManager() result = manager.format_for_prompt([]) assert result == "" def test_format_for_prompt(self): """Test formatting references for prompt.""" manager = CrossReferenceManager() refs = [ CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, reference_type=ReferenceType.ALLUSION, note="Echoes Genesis", translation_hint="Use similar phrasing", ) ] result = manager.format_for_prompt(refs) assert "CROSS-REFERENCES:" in result assert "ALLUSION" in result assert "genesis 1:1" in result assert "Echoes Genesis" in result assert "similar phrasing" in result def test_format_for_prompt_max_references(self): """Test formatting respects max_references limit.""" manager = CrossReferenceManager() refs = [ CrossReference( source_book="john", source_chapter=1, source_verse=i, target_book="genesis", target_chapter=1, target_verse_start=i, ) for i in range(1, 10) ] result = manager.format_for_prompt(refs, max_references=3) # Should only include 3 references assert result.count("genesis") == 3 def test_get_translation_consistency_notes(self): """Test getting consistency notes.""" manager = CrossReferenceManager() manager.add_reference( CrossReference( source_book="john", source_chapter=1, source_verse=23, target_book="isaiah", target_chapter=40, target_verse_start=3, reference_type=ReferenceType.QUOTATION, translation_hint="Match Isaiah translation", ) ) notes = manager.get_translation_consistency_notes("john", 1, 23) assert len(notes) > 0 assert any("quotes" in note for note in notes) assert any("Match Isaiah" in note for note in notes) def test_save_and_load(self): """Test saving and loading cross-references.""" with TemporaryDirectory() as tmpdir: data_dir = Path(tmpdir) metadata_dir = data_dir / "metadata" metadata_dir.mkdir(parents=True) # Create and populate manager manager = CrossReferenceManager() manager._data_dir = data_dir manager.add_reference( CrossReference( source_book="john", source_chapter=1, source_verse=1, target_book="genesis", target_chapter=1, target_verse_start=1, reference_type=ReferenceType.ALLUSION, ) ) # Save manager.save() # Load into new manager manager2 = CrossReferenceManager(data_dir) assert len(manager2) == 1 found = manager2.find_references_for_verse("john", 1, 1) assert len(found) == 1 assert found[0].target_book == "genesis" class TestJohnCrossReferences: """Tests for pre-defined John cross-references.""" def test_john_references_exist(self): """Test pre-defined John references exist.""" assert len(JOHN_CROSS_REFERENCES) > 0 def test_john_1_1_genesis_reference(self): """Test John 1:1 -> Genesis 1:1 reference.""" ref = next( (r for r in JOHN_CROSS_REFERENCES if r.source_book == "john" and r.source_chapter == 1 and r.source_verse == 1), None ) assert ref is not None assert ref.target_book == "genesis" assert ref.reference_type == ReferenceType.ALLUSION def test_all_references_valid(self): """Test all pre-defined references are valid.""" for ref in JOHN_CROSS_REFERENCES: assert ref.source_book == "john" assert ref.source_chapter >= 1 assert ref.source_verse >= 1 assert ref.target_chapter >= 1 assert ref.target_verse_start >= 1 class TestCreateDefaultCrossReferences: """Tests for create_default_cross_references.""" def test_creates_manager_with_defaults(self): """Test creating manager with default references.""" with TemporaryDirectory() as tmpdir: data_dir = Path(tmpdir) manager = create_default_cross_references(data_dir) assert len(manager) > 0