OPEN SOURCE
software/tests/test_output.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 for output formatters."""23import json4import pytest5from pathlib import Path67from src.data.storage import Storage8from src.models.verse import BookMetadata, TranslationOutput, VerseReference9from src.output.formatters import OutputFormatter101112@pytest.fixture13def temp_data_dir(tmp_path: Path) -> Path:14"""Create temporary data directory with translations."""15(tmp_path / "output" / "john").mkdir(parents=True)16(tmp_path / "progress").mkdir(parents=True)17return tmp_path181920@pytest.fixture21def storage_with_translations(temp_data_dir: Path) -> Storage:22"""Create storage with test translations."""23storage = Storage(temp_data_dir)2425# Add translations for John chapter 126for verse_num in range(1, 6):27ref = VerseReference(book="john", chapter=1, verse=verse_num)28output = TranslationOutput(29reference=ref,30text=f"ヨハネ第1章{verse_num}節の翻訳。",31model="test-model",32)33storage.save_translation(output)3435# Add translations for John chapter 236for verse_num in range(1, 4):37ref = VerseReference(book="john", chapter=2, verse=verse_num)38output = TranslationOutput(39reference=ref,40text=f"ヨハネ第2章{verse_num}節の翻訳。",41model="test-model",42)43storage.save_translation(output)4445return storage464748class TestOutputFormatter:49"""Tests for OutputFormatter."""5051def test_export_chapter_json(52self, storage_with_translations: Storage, tmp_path: Path53) -> None:54"""Test exporting chapter as JSON."""55formatter = OutputFormatter(storage_with_translations)56output_dir = tmp_path / "exports"5758path = formatter.export_chapter_json("john", 1, output_dir)5960assert path.exists()61with path.open("r", encoding="utf-8") as f:62data = json.load(f)6364assert data["book"] == "john"65assert data["chapter"] == 166assert len(data["verses"]) == 56768def test_export_chapter_text(69self, storage_with_translations: Storage, tmp_path: Path70) -> None:71"""Test exporting chapter as plain text."""72formatter = OutputFormatter(storage_with_translations)73output_dir = tmp_path / "exports"7475path = formatter.export_chapter_text("john", 1, output_dir)7677assert path.exists()78content = path.read_text(encoding="utf-8")7980assert "John Chapter 1" in content81assert "ヨハネ第1章1節の翻訳。" in content8283def test_export_chapter_html(84self, storage_with_translations: Storage, tmp_path: Path85) -> None:86"""Test exporting chapter as HTML."""87formatter = OutputFormatter(storage_with_translations)88output_dir = tmp_path / "exports"8990path = formatter.export_chapter_html("john", 1, output_dir)9192assert path.exists()93content = path.read_text(encoding="utf-8")9495assert "<!DOCTYPE html>" in content96assert '<html lang="ja">' in content97assert "ヨハネ第1章1節の翻訳。" in content9899def test_export_chapter_html_with_metadata(100self, storage_with_translations: Storage, tmp_path: Path101) -> None:102"""Test exporting chapter HTML with metadata."""103formatter = OutputFormatter(storage_with_translations)104output_dir = tmp_path / "exports"105106metadata = BookMetadata(107book="john",108name_japanese="ヨハネによる福音書",109name_english="Gospel of John",110testament="NT",111author="John",112themes=[],113description="Test",114chapter_count=21,115verse_count=879,116)117118path = formatter.export_chapter_html("john", 1, output_dir, metadata)119120content = path.read_text(encoding="utf-8")121assert "ヨハネによる福音書" in content122assert "第1章" in content123124def test_export_book_json(125self, storage_with_translations: Storage, tmp_path: Path126) -> None:127"""Test exporting entire book as JSON."""128formatter = OutputFormatter(storage_with_translations)129output_dir = tmp_path / "exports"130131path = formatter.export_book_json("john", output_dir)132133assert path.exists()134with path.open("r", encoding="utf-8") as f:135data = json.load(f)136137assert data["book"] == "john"138assert "1" in data["chapters"]139assert "2" in data["chapters"]140141def test_export_book_text(142self, storage_with_translations: Storage, tmp_path: Path143) -> None:144"""Test exporting entire book as plain text."""145formatter = OutputFormatter(storage_with_translations)146output_dir = tmp_path / "exports"147148path = formatter.export_book_text("john", output_dir)149150assert path.exists()151content = path.read_text(encoding="utf-8")152153assert "John" in content154assert "Chapter 1" in content155assert "Chapter 2" in content156157def test_export_book_json_empty(158self, temp_data_dir: Path, tmp_path: Path159) -> None:160"""Test exporting book with no translations."""161storage = Storage(temp_data_dir)162formatter = OutputFormatter(storage)163output_dir = tmp_path / "exports"164165path = formatter.export_book_json("matthew", output_dir)166167assert path.exists()168with path.open("r", encoding="utf-8") as f:169data = json.load(f)170171assert data["book"] == "matthew"172assert data["chapters"] == {}173174def test_export_book_text_empty(175self, temp_data_dir: Path, tmp_path: Path176) -> None:177"""Test exporting empty book as text."""178storage = Storage(temp_data_dir)179formatter = OutputFormatter(storage)180output_dir = tmp_path / "exports"181182path = formatter.export_book_text("matthew", output_dir)183184assert path.exists()185content = path.read_text(encoding="utf-8")186assert "Matthew" in content187188def test_export_creates_directory(189self, storage_with_translations: Storage, tmp_path: Path190) -> None:191"""Test export creates output directory if needed."""192formatter = OutputFormatter(storage_with_translations)193output_dir = tmp_path / "nested" / "deep" / "exports"194195path = formatter.export_chapter_json("john", 1, output_dir)196197assert path.exists()198assert output_dir.exists()199200def test_export_chapter_html_with_furigana(201self, temp_data_dir: Path, tmp_path: Path202) -> None:203"""Test exporting chapter HTML includes ruby tags for furigana."""204storage = Storage(temp_data_dir)205206# Create translation with furigana207ref = VerseReference(book="john", chapter=1, verse=1)208output = TranslationOutput(209reference=ref,210text="神は愛です",211text_with_furigana="神[かみ]は愛[あい]です",212furigana_annotations=[213{214"start_offset": 0,215"end_offset": 1,216"base_text": "神",217"reading": "かみ",218},219{220"start_offset": 2,221"end_offset": 3,222"base_text": "愛",223"reading": "あい",224},225],226model="test-model",227)228storage.save_translation(output)229230formatter = OutputFormatter(storage)231output_dir = tmp_path / "exports"232path = formatter.export_chapter_html("john", 1, output_dir)233234content = path.read_text(encoding="utf-8")235236# Check ruby tags are present237assert "<ruby>神<rt>かみ</rt></ruby>" in content238assert "<ruby>愛<rt>あい</rt></ruby>" in content239240def test_export_chapter_html_includes_ruby_css(241self, storage_with_translations: Storage, tmp_path: Path242) -> None:243"""Test HTML export includes CSS for ruby styling."""244formatter = OutputFormatter(storage_with_translations)245output_dir = tmp_path / "exports"246247path = formatter.export_chapter_html("john", 1, output_dir)248content = path.read_text(encoding="utf-8")249250assert "ruby { ruby-position: over; }" in content251assert "rt { font-size: 0.6em; color: #666; }" in content252253def test_export_chapter_html_fallback_without_furigana(254self, storage_with_translations: Storage, tmp_path: Path255) -> None:256"""Test HTML export falls back to plain text without furigana."""257formatter = OutputFormatter(storage_with_translations)258output_dir = tmp_path / "exports"259260path = formatter.export_chapter_html("john", 1, output_dir)261content = path.read_text(encoding="utf-8")262263# Original test translations don't have furigana, should use plain text264assert "ヨハネ第1章1節の翻訳。" in content265# Should not have any ruby tags for these translations266assert "<ruby>" not in content or "ヨハネ" not in content.split("<ruby>")[0]267