"""Regression fixtures for publication audit failures; no external dependencies.""" import importlib.util import json import sys import tempfile import unittest from pathlib import Path SCRIPTS = Path(__file__).resolve().parents[1] / 'scripts' spec = importlib.util.spec_from_file_location('verify_output', SCRIPTS / 'verify_output.py') verify = importlib.util.module_from_spec(spec) sys.modules[spec.name] = verify spec.loader.exec_module(verify) spec = importlib.util.spec_from_file_location('review_output', SCRIPTS / 'review_output.py') review = importlib.util.module_from_spec(spec) spec.loader.exec_module(review) class OutputAuditTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.root = Path(self.temp.name) self.baseline = {('genesis', 1, 1): '神が天と地を創造した。'} def write(self, verses=None, **metadata): directory = self.root / 'genesis' directory.mkdir(exist_ok=True) path = directory / 'chapter_01.json' path.write_text(json.dumps({'book': 'genesis', 'chapter': 1, 'verses': verses if verses is not None else {'1': {'text': '神が創造した。'}}, **metadata}), encoding='utf-8') return path def codes(self): return set(verify.audit(self.root, self.baseline)[0]['summary']['issues']) def test_complete_and_optional_furigana(self): for ruby in (None, '', '神が創造した。', '神かみが創造した。'): with self.subTest(ruby=ruby): self.write({'1': {'text': '神が創造した。', 'text_with_furigana': ruby}}) self.assertEqual(self.codes(), set()) def test_missing_source_fails_closed(self): report, _ = verify.audit(self.root / 'absent', self.baseline) self.assertFalse(report['passed']) self.assertIn('missing-source', report['summary']['issues']) def test_duplicate_json_key(self): self.write().write_text('{"verses":{"1":{},"1":{}}}') self.assertIn('invalid-json', self.codes()) def test_malformed_and_wrong_schema(self): for content in ('{', '[]', '{"verses": []}'): with self.subTest(content=content): self.write().write_text(content) self.assertTrue(self.codes() & {'invalid-json', 'invalid-schema'}) def test_mismatched_metadata(self): self.write(chapter=True) self.assertIn('metadata-mismatch', self.codes()) def test_missing_and_extra_verses(self): self.write({'2': {'text': '神が創造した。'}}) self.assertEqual(self.codes(), {'missing-verse', 'extra-verse'}) def test_empty_and_bad_number(self): self.write({'1': {'text': ''}, '02': {'text': '日本語'}}) self.assertTrue({'invalid-text', 'invalid-verse-number', 'missing-verse'} <= self.codes()) def test_extra_chapter_and_duplicate_alias(self): path = self.write() (path.parent / 'chapter_001.json').write_bytes(path.read_bytes()) self.assertTrue({'duplicate-chapter', 'duplicate-verse', 'noncanonical-filename'} <= self.codes()) (path.parent / 'chapter_02.json').write_bytes(path.read_bytes()) self.assertIn('unexpected-chapter', self.codes()) def test_text_hazards_and_stale_ruby(self): self.write({'1': {'text': '神\n\ufffd', 'text_with_furigana': '別の文'}}) self.assertTrue({'control-character', 'invalid-plain-text', 'furigana-mismatch'} <= self.codes()) def test_unexpected_files(self): self.write() (self.root / 'unknown').mkdir() self.assertIn('unexpected-path', self.codes()) def test_review_flags(self): rows = {('genesis', 1, 1): '翻訳結果 TODO λ', ('genesis', 1, 2): '翻訳結果 TODO λ'} queue = list(review.review(rows, self.baseline)) self.assertEqual(len(queue), 2) self.assertTrue({'latin-text', 'source-script', 'identical-within-chapter', 'placeholder-or-commentary'} <= set(queue[0]['flags'].split(';'))) def test_book_aliases(self): self.assertEqual(verify.book_id('III John'), '3john') self.assertEqual(verify.book_id('Revelation of John'), 'revelation') self.assertEqual(verify.book_id('song_of_solomon'), 'songofsolomon') if __name__ == '__main__': unittest.main()