OPEN SOURCE
software/tests/test_output_audit.py
このサイトで読み、必要なファイルを保存できます。
日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。
1"""Regression fixtures for publication audit failures; no external dependencies."""2import importlib.util3import json4import sys5import tempfile6import unittest7from pathlib import Path89SCRIPTS = Path(__file__).resolve().parents[1] / 'scripts'10spec = importlib.util.spec_from_file_location('verify_output', SCRIPTS / 'verify_output.py')11verify = importlib.util.module_from_spec(spec)12sys.modules[spec.name] = verify13spec.loader.exec_module(verify)14spec = importlib.util.spec_from_file_location('review_output', SCRIPTS / 'review_output.py')15review = importlib.util.module_from_spec(spec)16spec.loader.exec_module(review)171819class OutputAuditTests(unittest.TestCase):20def setUp(self):21self.temp = tempfile.TemporaryDirectory()22self.addCleanup(self.temp.cleanup)23self.root = Path(self.temp.name)24self.baseline = {('genesis', 1, 1): '神が天と地を創造した。'}2526def write(self, verses=None, **metadata):27directory = self.root / 'genesis'28directory.mkdir(exist_ok=True)29path = directory / 'chapter_01.json'30path.write_text(json.dumps({'book': 'genesis', 'chapter': 1,31'verses': verses if verses is not None else {'1': {'text': '神が創造した。'}},32**metadata}), encoding='utf-8')33return path3435def codes(self):36return set(verify.audit(self.root, self.baseline)[0]['summary']['issues'])3738def test_complete_and_optional_furigana(self):39for ruby in (None, '', '神が創造した。', '<ruby>神<rt>かみ</rt></ruby>が創造した。'):40with self.subTest(ruby=ruby):41self.write({'1': {'text': '神が創造した。', 'text_with_furigana': ruby}})42self.assertEqual(self.codes(), set())4344def test_missing_source_fails_closed(self):45report, _ = verify.audit(self.root / 'absent', self.baseline)46self.assertFalse(report['passed'])47self.assertIn('missing-source', report['summary']['issues'])4849def test_duplicate_json_key(self):50self.write().write_text('{"verses":{"1":{},"1":{}}}')51self.assertIn('invalid-json', self.codes())5253def test_malformed_and_wrong_schema(self):54for content in ('{', '[]', '{"verses": []}'):55with self.subTest(content=content):56self.write().write_text(content)57self.assertTrue(self.codes() & {'invalid-json', 'invalid-schema'})5859def test_mismatched_metadata(self):60self.write(chapter=True)61self.assertIn('metadata-mismatch', self.codes())6263def test_missing_and_extra_verses(self):64self.write({'2': {'text': '神が創造した。'}})65self.assertEqual(self.codes(), {'missing-verse', 'extra-verse'})6667def test_empty_and_bad_number(self):68self.write({'1': {'text': ''}, '02': {'text': '日本語'}})69self.assertTrue({'invalid-text', 'invalid-verse-number', 'missing-verse'} <= self.codes())7071def test_extra_chapter_and_duplicate_alias(self):72path = self.write()73(path.parent / 'chapter_001.json').write_bytes(path.read_bytes())74self.assertTrue({'duplicate-chapter', 'duplicate-verse', 'noncanonical-filename'} <= self.codes())75(path.parent / 'chapter_02.json').write_bytes(path.read_bytes())76self.assertIn('unexpected-chapter', self.codes())7778def test_text_hazards_and_stale_ruby(self):79self.write({'1': {'text': '神\n<script>悪</script>\ufffd', 'text_with_furigana': '別の文'}})80self.assertTrue({'control-character', 'invalid-plain-text', 'furigana-mismatch'} <= self.codes())8182def test_unexpected_files(self):83self.write()84(self.root / 'unknown').mkdir()85self.assertIn('unexpected-path', self.codes())8687def test_review_flags(self):88rows = {('genesis', 1, 1): '翻訳結果 TODO λ', ('genesis', 1, 2): '翻訳結果 TODO λ'}89queue = list(review.review(rows, self.baseline))90self.assertEqual(len(queue), 2)91self.assertTrue({'latin-text', 'source-script', 'identical-within-chapter',92'placeholder-or-commentary'} <= set(queue[0]['flags'].split(';')))9394def test_book_aliases(self):95self.assertEqual(verify.book_id('III John'), '3john')96self.assertEqual(verify.book_id('Revelation of John'), 'revelation')97self.assertEqual(verify.book_id('song_of_solomon'), 'songofsolomon')9899100if __name__ == '__main__':101unittest.main()102