Pre-publication review draft
日常訳NICHIJOYAKU日本語 ↗

OPEN SOURCE

software/tests/test_widgets_extended.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

software/tests/test_widgets_extended.py420 linesDownload this file ↓

This is the same source included in the download. Each line number is a link you can save or share.

File verification detailsSHA-256 5de4db37b363df43a4c9eacc6c2bffd11a3a435670ea2344789f76bf35396bb0
1"""Extended tests for TUI widgets to improve coverage."""23import json4from datetime import datetime5from io import StringIO6from pathlib import Path78import pytest9from rich.console import Console10from rich.text import Text1112from src.models.evaluation import (13    EvaluationScore,14    VerseEvaluation,15)16from src.tui.data_provider import TUIDataProvider, VerseData17from src.tui.widgets import (18    ChapterQualitySummary,19    DetailPanel,20    EvaluationSummaryTable,21)222324@pytest.fixture25def temp_data_dir(tmp_path: Path) -> Path:26    """Create a temporary data directory with test data."""27    # Create source directories28    sources_dir = tmp_path / "sources"29    (sources_dir / "greek").mkdir(parents=True)30    (sources_dir / "english" / "kjv").mkdir(parents=True)3132    # Create Greek source33    greek_data = {"1:1": {"text": "Ἐν ἀρχῇ", "translit": "En archē"}}34    with (sources_dir / "greek" / "john.json").open("w") as f:35        json.dump(greek_data, f)3637    # Create KJV source38    kjv_data = {"1:1": "In the beginning was the Word"}39    with (sources_dir / "english" / "kjv" / "john.json").open("w") as f:40        json.dump(kjv_data, f)4142    # Create output directory with translations43    output_dir = tmp_path / "output" / "john"44    output_dir.mkdir(parents=True)4546    chapter_data = {47        "book": "john",48        "chapter": 1,49        "verses": {50            "1": {51                "text": "初めに言葉があった。",52                "model": "claude-sonnet-4",53                "timestamp": "2026-01-13T00:00:00Z",54                "glossary_terms_applied": [],55            },56        },57    }58    with (output_dir / "chapter_01.json").open("w") as f:59        json.dump(chapter_data, f)6061    # Create evaluation file with all score levels62    eval_data = {63        "book": "john",64        "chapter": 1,65        "evaluator_model": "claude-opus-4-5",66        "evaluated_at": "2026-01-13T00:00:00Z",67        "verses": {68            "1": {69                "scores": {70                    "theological_accuracy": {71                        "score": 95,72                        "confidence": 90,73                        "reasoning": "Excellent",74                    },75                    "source_fidelity": {76                        "score": 75,77                        "confidence": 85,78                        "reasoning": "Good but could improve",79                    },80                    "naturalness": {81                        "score": 65,82                        "confidence": 80,83                        "reasoning": "Below threshold",84                    },85                },86                "overall_score": 78.3,87                "flags": ["naturalness_concern"],88                "notes": "Consider improving naturalness",89                "timestamp": "2026-01-13T00:00:00Z",90            },91        },92        "aggregate": {93            "scores": {94                "theological_accuracy": 95.0,95                "source_fidelity": 75.0,96                "naturalness": 65.0,97            },98            "overall": 78.3,99            "flagged_count": 1,100            "flagged_verses": [1],101        },102    }103    with (output_dir / "chapter_01_eval.json").open("w") as f:104        json.dump(eval_data, f)105106    # Create metadata directory107    metadata_dir = tmp_path / "metadata"108    metadata_dir.mkdir(parents=True)109110    return tmp_path111112113def _render_to_string(renderable) -> str:114    """Render content to a string for testing."""115    console = Console(file=StringIO(), force_terminal=True, width=120)116    console.print(renderable)117    return console.file.getvalue()118119120class TestDetailPanelScoreColors:121    """Tests for DetailPanel score color coding."""122123    def test_render_with_excellent_score(self, temp_data_dir: Path) -> None:124        """Test rendering with excellent score (>= 90)."""125        provider = TUIDataProvider(temp_data_dir)126        panel = DetailPanel(provider, id="detail")127128        # Create verse data with excellent score129        panel.current_verse = VerseData(130            book="john",131            chapter=1,132            verse=1,133            greek_text="Ἐν ἀρχῇ",134            kjv_text="In the beginning",135            japanese_reference=None,136            glossary_terms=[],137            translation_text="初めに言葉があった。",138            translation_model="claude-sonnet-4",139            translation_timestamp="2026-01-13",140            evaluation=VerseEvaluation(141                verse_number=1,142                evaluator_model="test",143                timestamp=datetime.utcnow(),144                scores={145                    "theological_accuracy": EvaluationScore(146                        dimension="theological_accuracy",147                        score=95.0,148                        confidence=90.0,149                        reasoning="Excellent",150                    ),151                },152                flags=[],153                notes=None,154            ),155        )156157        rendered_str = _render_to_string(panel.render())158        # Should show excellent score indicator159        assert "95" in rendered_str160161    def test_render_with_concern_score(self, temp_data_dir: Path) -> None:162        """Test rendering with concerning score (< 70)."""163        provider = TUIDataProvider(temp_data_dir)164        panel = DetailPanel(provider, id="detail")165166        # Create verse data with low score167        panel.current_verse = VerseData(168            book="john",169            chapter=1,170            verse=1,171            greek_text="Ἐν ἀρχῇ",172            kjv_text="In the beginning",173            japanese_reference=None,174            glossary_terms=[],175            translation_text="初めに言葉があった。",176            translation_model="claude-sonnet-4",177            translation_timestamp="2026-01-13",178            evaluation=VerseEvaluation(179                verse_number=1,180                evaluator_model="test",181                timestamp=datetime.utcnow(),182                scores={183                    "naturalness": EvaluationScore(184                        dimension="naturalness",185                        score=55.0,186                        confidence=80.0,187                        reasoning="Needs work",188                    ),189                },190                flags=["naturalness_concern"],191                notes="Needs improvement",192            ),193        )194195        rendered_str = _render_to_string(panel.render())196        assert "55" in rendered_str197198    def test_render_with_multiple_flags(self, temp_data_dir: Path) -> None:199        """Test rendering verse with multiple flags."""200        provider = TUIDataProvider(temp_data_dir)201        panel = DetailPanel(provider, id="detail")202203        panel.current_verse = VerseData(204            book="john",205            chapter=1,206            verse=1,207            greek_text="Ἐν ἀρχῇ",208            kjv_text="In the beginning",209            japanese_reference=None,210            glossary_terms=[],211            translation_text="初めに言葉があった。",212            translation_model="claude-sonnet-4",213            translation_timestamp="2026-01-13",214            evaluation=VerseEvaluation(215                verse_number=1,216                evaluator_model="test",217                timestamp=datetime.utcnow(),218                scores={219                    "theological_accuracy": EvaluationScore(220                        dimension="theological_accuracy",221                        score=60.0,222                        confidence=70.0,223                        reasoning="Concern",224                    ),225                    "source_fidelity": EvaluationScore(226                        dimension="source_fidelity",227                        score=55.0,228                        confidence=65.0,229                        reasoning="Issue",230                    ),231                },232                flags=["theological_concern", "source_fidelity_concern"],233                notes="Multiple issues",234            ),235        )236237        rendered_str = _render_to_string(panel.render())238        # Should contain flag indicators239        assert "concern" in rendered_str.lower() or "flag" in rendered_str.lower()240241242class TestEvaluationSummaryTableScoreBars:243    """Tests for EvaluationSummaryTable visual bars."""244245    def test_render_with_varied_scores(self) -> None:246        """Test rendering with various score levels."""247        table = EvaluationSummaryTable(id="eval-table")248        table.set_scores({249            "theological_accuracy": (95.0, 90.0),  # Excellent250            "source_fidelity": (75.0, 85.0),  # Good251            "naturalness": (55.0, 80.0),  # Concern252            "readability": (85.0, 90.0),  # Good253            "glossary_consistency": (100.0, 100.0),  # Perfect254            "literary_quality": (65.0, 75.0),  # Below threshold255        })256257        rendered_str = _render_to_string(table.render())258259        # Should contain all dimension scores260        assert "95" in rendered_str261        assert "75" in rendered_str262        assert "55" in rendered_str263264    def test_render_with_scores_uses_bars(self) -> None:265        """Test rendering includes visual bars."""266        table = EvaluationSummaryTable(id="eval-table")267        table.set_scores({"theological_accuracy": (90.0, 95.0)})268269        rendered_str = _render_to_string(table.render())270        # Should contain bar characters271        assert "█" in rendered_str or "░" in rendered_str272273274class TestChapterQualitySummary:275    """Tests for ChapterQualitySummary widget."""276277    def test_render_empty(self, temp_data_dir: Path) -> None:278        """Test rendering with no chapter selected."""279        provider = TUIDataProvider(temp_data_dir)280        widget = ChapterQualitySummary(provider, id="quality-summary")281        rendered = widget.render()282        rendered_str = _render_to_string(rendered)283        assert "Select a chapter" in rendered_str or "Chapter" in rendered_str284285    def test_render_with_chapter_data(self, temp_data_dir: Path) -> None:286        """Test rendering with chapter selected."""287        provider = TUIDataProvider(temp_data_dir)288        widget = ChapterQualitySummary(provider, id="quality-summary")289        widget.update_chapter("john", 1)290291        rendered_str = _render_to_string(widget.render())292        # Should show chapter info293        assert "JOHN" in rendered_str or "john" in rendered_str.lower()294295    def test_render_with_no_eval_data(self, temp_data_dir: Path) -> None:296        """Test rendering chapter with no evaluation."""297        provider = TUIDataProvider(temp_data_dir)298        widget = ChapterQualitySummary(provider, id="quality-summary")299        # Select a chapter that doesn't have evaluation300        widget.update_chapter("john", 99)301302        rendered_str = _render_to_string(widget.render())303        assert "No evaluation" in rendered_str or "--evaluate" in rendered_str304305306class TestDimensionNameFormatting:307    """Tests for dimension name formatting in widgets."""308309    def test_format_dimension_names_table(self) -> None:310        """Test dimension name formatting in EvaluationSummaryTable."""311        table = EvaluationSummaryTable(id="eval-table")312313        # Test that dimension names are formatted314        formatted = table._format_dimension_name("theological_accuracy")315        assert "Theolog" in formatted or "theological" in formatted.lower()316317        formatted = table._format_dimension_name("source_fidelity")318        assert "Fidelity" in formatted or "source" in formatted.lower()319320        formatted = table._format_dimension_name("glossary_consistency")321        assert "Glossary" in formatted or "consistency" in formatted.lower()322323    def test_format_dimension_names_panel(self, temp_data_dir: Path) -> None:324        """Test dimension name formatting in DetailPanel."""325        provider = TUIDataProvider(temp_data_dir)326        panel = DetailPanel(provider, id="detail")327328        formatted = panel._format_dimension_name("theological_accuracy")329        assert "Theolog" in formatted330331        formatted = panel._format_dimension_name("unknown_dimension")332        # Unknown dimensions should be title-cased333        assert "Unknown" in formatted or "Dimension" in formatted334335336class TestScoreColorHelpers:337    """Tests for score color helper methods."""338339    def test_get_score_color_excellent(self) -> None:340        """Test color for excellent scores."""341        table = EvaluationSummaryTable(id="eval-table")342        color = table._get_score_color(95.0)343        assert color == "green"344345    def test_get_score_color_good(self) -> None:346        """Test color for good scores."""347        table = EvaluationSummaryTable(id="eval-table")348        color = table._get_score_color(80.0)349        assert color == "yellow"350351    def test_get_score_color_concern(self) -> None:352        """Test color for concerning scores."""353        table = EvaluationSummaryTable(id="eval-table")354        color = table._get_score_color(65.0)355        assert color == "orange1"356357    def test_get_score_color_poor(self) -> None:358        """Test color for poor scores."""359        table = EvaluationSummaryTable(id="eval-table")360        color = table._get_score_color(50.0)361        assert color == "red"362363364class TestDetailPanelHelpers:365    """Tests for DetailPanel helper methods."""366367    def test_get_quality_indicator_excellent(self, temp_data_dir: Path) -> None:368        """Test indicator for excellent quality."""369        provider = TUIDataProvider(temp_data_dir)370        panel = DetailPanel(provider, id="detail")371        indicator = panel._get_quality_indicator(95.0)372        assert indicator == "●"373374    def test_get_quality_indicator_good(self, temp_data_dir: Path) -> None:375        """Test indicator for good quality."""376        provider = TUIDataProvider(temp_data_dir)377        panel = DetailPanel(provider, id="detail")378        indicator = panel._get_quality_indicator(80.0)379        assert indicator == "◐"380381    def test_get_quality_indicator_concern(self, temp_data_dir: Path) -> None:382        """Test indicator for concerning quality."""383        provider = TUIDataProvider(temp_data_dir)384        panel = DetailPanel(provider, id="detail")385        indicator = panel._get_quality_indicator(65.0)386        assert indicator == "○"387388    def test_get_quality_indicator_poor(self, temp_data_dir: Path) -> None:389        """Test indicator for poor quality."""390        provider = TUIDataProvider(temp_data_dir)391        panel = DetailPanel(provider, id="detail")392        indicator = panel._get_quality_indicator(50.0)393        assert indicator == "✗"394395396class TestFlagFormatting:397    """Tests for flag formatting in DetailPanel."""398399    def test_format_flag_theological(self, temp_data_dir: Path) -> None:400        """Test formatting theological flag."""401        provider = TUIDataProvider(temp_data_dir)402        panel = DetailPanel(provider, id="detail")403        formatted = panel._format_flag("theological_concern")404        assert "theological" in formatted or "concern" in formatted405406    def test_format_flag_source(self, temp_data_dir: Path) -> None:407        """Test formatting source fidelity flag."""408        provider = TUIDataProvider(temp_data_dir)409        panel = DetailPanel(provider, id="detail")410        formatted = panel._format_flag("source_fidelity_concern")411        assert "source" in formatted or "fidelity" in formatted412413    def test_format_flag_with_low(self, temp_data_dir: Path) -> None:414        """Test formatting flag with 'low' keyword."""415        provider = TUIDataProvider(temp_data_dir)416        panel = DetailPanel(provider, id="detail")417        formatted = panel._format_flag("low_confidence")418        # 'low' should be replaced with arrow419        assert "↓" in formatted or "confidence" in formatted420