公開前の確認用サイト
日常訳NICHIJOYAKUEnglish ↗

OPEN SOURCE

software/tests/test_context.py

このサイトで読み、必要なファイルを保存できます。

日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。

← オープンソースの案内へ

software/tests/test_context.py295 行このファイルを保存 ↓

ZIPに含まれるものと同じ公開ソースです。行番号から、その行へのリンクを保存できます。

ファイルの確認情報SHA-256 810e2d170843535cd0ba66294c2f5746a831d4952ba54b1119ce8f09952b1a32
1"""Tests for context building and glossary management."""23import json4import pytest5from pathlib import Path67from src.context.builder import ContextBuilder8from src.context.glossary import GlossaryManager9from src.data.loader import DataLoader10from src.models.verse import GlossaryTerm, VerseReference111213@pytest.fixture14def glossary_terms() -> list[GlossaryTerm]:15    """Create test glossary terms."""16    return [17        GlossaryTerm(18            original="λόγος",19            transliteration="logos",20            japanese="言葉",21            english="word",22            notes="The Word",23        ),24        GlossaryTerm(25            original="θεός",26            transliteration="theos",27            japanese="神",28            english="God",29        ),30        GlossaryTerm(31            original="ἀγάπη",32            transliteration="agape",33            japanese="愛",34            english="love",35        ),36    ]373839@pytest.fixture40def temp_data_dir(tmp_path: Path) -> Path:41    """Create temporary data directory with test data."""42    sources_dir = tmp_path / "sources"43    (sources_dir / "greek").mkdir(parents=True)44    (sources_dir / "japanese" / "meiji").mkdir(parents=True)45    (sources_dir / "japanese" / "taisho").mkdir(parents=True)46    (sources_dir / "english" / "kjv").mkdir(parents=True)47    (sources_dir / "english" / "asv").mkdir(parents=True)48    (tmp_path / "metadata" / "john").mkdir(parents=True)4950    # Greek data with 5 verses51    greek_data = {52        "1:1": {"text": "Ἐν ἀρχῇ ἦν ὁ λόγος", "translit": "En archē ēn ho logos"},53        "1:2": {"text": "οὗτος ἦν ἐν ἀρχῇ", "translit": "houtos ēn en archē"},54        "1:3": {"text": "πάντα δι' αὐτοῦ ἐγένετο", "translit": "panta di autou egeneto"},55        "1:4": {"text": "ἐν αὐτῷ ζωὴ ἦν", "translit": "en autō zōē ēn"},56        "1:5": {"text": "τὸ φῶς ἐν τῇ σκοτίᾳ", "translit": "to phōs en tē skotia"},57    }58    with (sources_dir / "greek" / "john.json").open("w") as f:59        json.dump(greek_data, f)6061    # KJV data62    kjv_data = {63        "1:1": "In the beginning was the Word",64        "1:2": "The same was in the beginning with God",65        "1:3": "All things were made by him",66        "1:4": "In him was life",67        "1:5": "And the light shineth in darkness",68    }69    with (sources_dir / "english" / "kjv" / "john.json").open("w") as f:70        json.dump(kjv_data, f)7172    # Book metadata73    book_metadata = {74        "book": "john",75        "name_japanese": "ヨハネによる福音書",76        "name_english": "Gospel of John",77        "testament": "NT",78        "author": "John the Apostle",79        "themes": ["love", "light"],80        "description": "The fourth Gospel",81        "chapter_count": 21,82        "verse_count": 879,83    }84    with (tmp_path / "metadata" / "john" / "book_context.json").open("w") as f:85        json.dump(book_metadata, f)8687    # Chapter summaries88    chapter_summaries = {89        "1": {90            "summary": "The prologue introduces Jesus as the Word",91            "key_events": ["Word becomes flesh"],92            "key_characters": ["Jesus", "John"],93            "key_themes": ["Light", "Word"],94        }95    }96    with (tmp_path / "metadata" / "john" / "chapter_summaries.json").open("w") as f:97        json.dump(chapter_summaries, f)9899    # Glossary100    glossary = {101        "terms": [102            {103                "original": "λόγος",104                "transliteration": "logos",105                "japanese": "言葉",106                "english": "word",107                "notes": "The Word",108            }109        ]110    }111    with (tmp_path / "metadata" / "glossary.json").open("w") as f:112        json.dump(glossary, f)113114    return tmp_path115116117class TestGlossaryManager:118    """Tests for GlossaryManager."""119120    def test_init_empty(self) -> None:121        """Test initializing empty glossary."""122        glossary = GlossaryManager()123        assert len(glossary) == 0124125    def test_init_with_terms(self, glossary_terms: list[GlossaryTerm]) -> None:126        """Test initializing with terms."""127        glossary = GlossaryManager(glossary_terms)128        assert len(glossary) == 3129130    def test_add_term(self) -> None:131        """Test adding a term."""132        glossary = GlossaryManager()133        term = GlossaryTerm(134            original="λόγος",135            transliteration="logos",136            japanese="言葉",137            english="word",138        )139        glossary.add_term(term)140        assert len(glossary) == 1141142    def test_get_by_original(self, glossary_terms: list[GlossaryTerm]) -> None:143        """Test getting term by original."""144        glossary = GlossaryManager(glossary_terms)145        term = glossary.get_by_original("λόγος")146        assert term is not None147        assert term.japanese == "言葉"148149    def test_get_by_original_not_found(150        self, glossary_terms: list[GlossaryTerm]151    ) -> None:152        """Test getting non-existent term."""153        glossary = GlossaryManager(glossary_terms)154        term = glossary.get_by_original("nonexistent")155        assert term is None156157    def test_get_by_transliteration(158        self, glossary_terms: list[GlossaryTerm]159    ) -> None:160        """Test getting term by transliteration."""161        glossary = GlossaryManager(glossary_terms)162        term = glossary.get_by_transliteration("logos")163        assert term is not None164        assert term.original == "λόγος"165166    def test_get_by_transliteration_case_insensitive(167        self, glossary_terms: list[GlossaryTerm]168    ) -> None:169        """Test transliteration lookup is case insensitive."""170        glossary = GlossaryManager(glossary_terms)171        term = glossary.get_by_transliteration("LOGOS")172        assert term is not None173174    def test_find_terms_in_text_by_original(175        self, glossary_terms: list[GlossaryTerm]176    ) -> None:177        """Test finding terms by original in text."""178        glossary = GlossaryManager(glossary_terms)179        found = glossary.find_terms_in_text("Ἐν ἀρχῇ ἦν ὁ λόγος")180        assert len(found) == 1181        assert found[0].original == "λόγος"182183    def test_find_terms_in_text_by_transliteration(184        self, glossary_terms: list[GlossaryTerm]185    ) -> None:186        """Test finding terms by transliteration in text."""187        glossary = GlossaryManager(glossary_terms)188        found = glossary.find_terms_in_text("en archē ēn ho logos")189        assert len(found) == 1190        assert found[0].original == "λόγος"191192    def test_find_terms_in_text_multiple(193        self, glossary_terms: list[GlossaryTerm]194    ) -> None:195        """Test finding multiple terms."""196        glossary = GlossaryManager(glossary_terms)197        found = glossary.find_terms_in_text("λόγος and θεός")198        assert len(found) == 2199200    def test_find_terms_no_duplicates(201        self, glossary_terms: list[GlossaryTerm]202    ) -> None:203        """Test no duplicate terms returned."""204        glossary = GlossaryManager(glossary_terms)205        # Text with both original and transliteration206        found = glossary.find_terms_in_text("λόγος logos")207        assert len(found) == 1208209    def test_get_all_terms(self, glossary_terms: list[GlossaryTerm]) -> None:210        """Test getting all terms."""211        glossary = GlossaryManager(glossary_terms)212        all_terms = glossary.get_all_terms()213        assert len(all_terms) == 3214215    def test_format_for_prompt_with_terms(216        self, glossary_terms: list[GlossaryTerm]217    ) -> None:218        """Test formatting terms for prompt."""219        glossary = GlossaryManager(glossary_terms)220        formatted = glossary.format_for_prompt(glossary_terms[:2])221        assert "λόγος" in formatted222        assert "言葉" in formatted223        assert "[The Word]" in formatted  # Notes should be included224225    def test_format_for_prompt_empty(self) -> None:226        """Test formatting empty list."""227        glossary = GlossaryManager()228        formatted = glossary.format_for_prompt([])229        assert "No specific glossary" in formatted230231232class TestContextBuilder:233    """Tests for ContextBuilder."""234235    def test_build_context(self, temp_data_dir: Path) -> None:236        """Test building translation context."""237        loader = DataLoader(temp_data_dir)238        glossary = GlossaryManager(loader.load_glossary())239        builder = ContextBuilder(loader, glossary)240241        ref = VerseReference(book="john", chapter=1, verse=3)242        context = builder.build_context(ref)243244        assert context.target_verse.reference == ref245        assert len(context.preceding_verses) > 0246        assert len(context.following_verses) > 0247248    def test_build_context_first_verse(self, temp_data_dir: Path) -> None:249        """Test context for first verse has no preceding."""250        loader = DataLoader(temp_data_dir)251        glossary = GlossaryManager(loader.load_glossary())252        builder = ContextBuilder(loader, glossary)253254        ref = VerseReference(book="john", chapter=1, verse=1)255        context = builder.build_context(ref)256257        assert len(context.preceding_verses) == 0258259    def test_build_context_with_metadata(self, temp_data_dir: Path) -> None:260        """Test context includes metadata."""261        loader = DataLoader(temp_data_dir)262        glossary = GlossaryManager(loader.load_glossary())263        builder = ContextBuilder(loader, glossary)264265        ref = VerseReference(book="john", chapter=1, verse=1)266        context = builder.build_context(ref)267268        assert context.book_metadata is not None269        assert context.chapter_summary is not None270271    def test_build_context_finds_glossary_terms(self, temp_data_dir: Path) -> None:272        """Test context finds glossary terms in verse."""273        loader = DataLoader(temp_data_dir)274        glossary = GlossaryManager(loader.load_glossary())275        builder = ContextBuilder(loader, glossary)276277        ref = VerseReference(book="john", chapter=1, verse=1)278        context = builder.build_context(ref)279280        # John 1:1 has λόγος which is in our glossary281        assert len(context.glossary_terms) > 0282283    def test_context_window_size(self, temp_data_dir: Path) -> None:284        """Test context window size parameter."""285        loader = DataLoader(temp_data_dir)286        glossary = GlossaryManager()287        builder = ContextBuilder(loader, glossary, context_window=2)288289        ref = VerseReference(book="john", chapter=1, verse=3)290        context = builder.build_context(ref)291292        # Should have at most 2 preceding and 2 following293        assert len(context.preceding_verses) <= 2294        assert len(context.following_verses) <= 2295