OPEN SOURCE
software/tests/test_versification.py
このサイトで読み、必要なファイルを保存できます。
日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。
1"""Regression cases for shifted chapters, partial verses and mixed languages."""2import json3import shutil4from pathlib import Path56import pytest78from src.data.versification import DATA, load_map, spans_for, build_originals9from src.output.originals import group_segments, build101112def words(count, replacement=None):13result = [{'word': f'w{i}', 'morph': 'HNp'} for i in range(count)]14if replacement:15index, text = replacement16result[index]['word'] = text17return {'words': result}181920def test_cross_chapter_and_heading_maps():21mapping = load_map()22assert mapping['joel', 4, 1] == [(3, 1, 0, None)]23assert mapping['genesis', 32, 1] == [(31, 55, 0, None)]24assert mapping['psalms', 3, 1] == [(3, 0, 0, None)]25assert mapping['psalms', 51, 1] == [(51, 0, 0, None)]26assert mapping['psalms', 51, 2] == [(51, 0, 0, None)]27assert mapping['3john', 1, 15] == [(1, 14, 0, None)]28assert mapping['revelation', 12, 18] == [(12, 17, 0, None)]293031@pytest.mark.parametrize('key,count,boundary,expected', [32(('1kings',18,34),16,(10,'ויאמר'),[(('1kings',18,33),0,10),(('1kings',18,34),10,16)]),33(('1kings',20,3),15,(6,'כספך'),[(('1kings',20,2),0,6),(('1kings',20,3),6,15)]),34(('1kings',22,21),12,(8,'ויאמר'),[(('1kings',22,21),0,8),(('1kings',22,22),8,12)]),35(('1kings',22,44),9,None,[(('1kings',22,43),0,9)]),36(('isaiah',63,19),16,(9,'לוא'),[(('isaiah',63,19),0,9),(('isaiah',64,1),9,16)]),37(('psalms',13,6),11,(6,'אשירה'),[(('psalms',13,5),0,6),(('psalms',13,6),6,11)]),38(('zechariah',2,15),18,(12,'וידעת'),[(('zechariah',2,11),0,12),(('zechariah',2,12),12,18)]),39])40def test_partial_boundaries(key,count,boundary,expected):41assert spans_for(*key, words(count,boundary), load_map()) == expected424344def test_acts_closing_sentence_and_source_drift():45record=words(2)46record['words'] += [{'word': w} for w in 'καὶ ταῦτα εἰπὼν ἀπέλυσεν τὴν ἐκκλησίαν'.split()]47assert spans_for('acts',19,40,record,{}) == [(('acts',19,40),0,2),(('acts',19,41),2,8)]48with pytest.raises(ValueError,match='closing sentence'):49spans_for('acts',19,40,words(10),{})50with pytest.raises(ValueError,match='boundary'):51spans_for('isaiah',63,19,words(16),load_map())525354def test_invalid_spans_fail_closed():55key=('genesis',1,1)56for spans in [[(1,1,0,0)],[(1,1,0,8)]]:57with pytest.raises(ValueError,match='Invalid word span'):58spans_for(*key,words(3),{key:spans})59with pytest.raises(ValueError,match='loss or duplication'):60spans_for(*key,words(3),{key:[(1,1,0,2),(1,2,1,3)]})616263def test_map_changes_rejected(tmp_path):64original=(DATA/'versification/oshb-VerseMap.xml').read_text()65p=tmp_path/'map.xml'66p.write_text(original.replace('type="partial"','type="unsupported"',1))67with pytest.raises(ValueError,match='Unknown map type'):load_map(p)68p.write_text(original.replace('type="partial"','type="full"',1))69with pytest.raises(ValueError,match='Partial verse map changed'):load_map(p)70line='<verse wlc="Gen.32.1" kjv="Gen.31.55" type="full"/>'71p.write_text(original.replace(line,line+line))72with pytest.raises(ValueError,match='Duplicate'):load_map(p)737475def test_language_runs_and_word_conservation(tmp_path):76(tmp_path/'versification').mkdir()77shutil.copy(DATA/'versification/oshb-VerseMap.xml',tmp_path/'versification/oshb-VerseMap.xml')78for language,book,record in [79('hebrew','genesis',{'words':[{'word':'א/ב','morph':'HNp'},{'word':'גד','morph':'ANp'},{'word':'הו','morph':'HNp'}]}),80('greek','john',{'words':[{'word':'λόγος'},{'word':'θεός'}]}),81]:82path=tmp_path/'sources'/language;path.mkdir(parents=True)83(path/f'{book}.json').write_text(json.dumps({'1:1':record}))84result,mapping=build_originals(tmp_path)85assert sum(map(len,result.values()))==586assert [w['language'] for w in result['genesis',1,1]]==['he','arc','he']87assert result['genesis',1,1][0]['text']=='אב'88assert group_segments(result['john',1,1])==[{'language':'grc','source':'john:1:1','text':'λόγος θεός'}]89assert len(mapping)==2909192def test_export_never_overwrites_source_data(tmp_path):93with pytest.raises(ValueError,match='outside translator data'):94build(tmp_path/'output',data_dir=tmp_path)959697def test_unknown_language_tag_rejected(tmp_path):98(tmp_path/'versification').mkdir()99shutil.copy(DATA/'versification/oshb-VerseMap.xml',tmp_path/'versification/oshb-VerseMap.xml')100(tmp_path/'sources/hebrew').mkdir(parents=True)101(tmp_path/'sources/hebrew/genesis.json').write_text(json.dumps({'1:1':{'words':[{'word':'אב','morph':'?'}]}}))102with pytest.raises(ValueError,match='Unknown word language'):build_originals(tmp_path)103104105def test_export_includes_headings_omissions_hashes_and_language_runs(tmp_path,monkeypatch):106from src.output import originals107data=tmp_path/'input';(data/'versification').mkdir(parents=True)108(data/'versification/oshb-VerseMap.xml').write_text('fixture')109source=data/'sources/hebrew';source.mkdir(parents=True)110(source/'psalms.json').write_text('{}')111monkeypatch.setattr(originals,'load_site',lambda _: ({('psalms',3,1):'本文',('psalms',3,2):'本文'}, {'psalms':'ps'}))112original_words={('psalms',3,0):[{'language':'he','text':'דוד','source':'psalms:3:1','word':0}],('psalms',3,1):[{'language':'he','text':'יהוה','source':'psalms:3:2','word':0}]}113monkeypatch.setattr(originals,'build_originals',lambda _: (original_words,{('psalms',3,1):[(('psalms',3,0),0,1)],('psalms',3,2):[(('psalms',3,1),0,1)]}))114out=tmp_path/'out';report=originals.build(out,data)115payload=json.loads((out/'ps.json').read_text())116assert payload['chapters']['3']['heading'][0]['text']=='דוד'117assert payload['chapters']['3']['verses']['2']==[]118assert report['without_original']==['psalms:3:2']119assert report['words_by_language']=={'he':2}120assert report['mapped_source_references']==2121assert len(report['files']['ps.json'])==64122original_words[('psalms',3,3)]=[]123with pytest.raises(ValueError,match='outside site'):originals.build(out,data)124125126def test_site_reference_validation(tmp_path):127from src.output.originals import load_site,normalize_book128assert normalize_book('III John')=='3john'129assert normalize_book('II Corinthians')=='2corinthians'130assert normalize_book('I Samuel')=='1samuel'131assert normalize_book('Song of Solomon')=='song_of_solomon'132refs,codes=load_site()133assert len(refs)==31101 and len(codes)==66134(tmp_path/'src/lib').mkdir(parents=True)135(tmp_path/'public').mkdir()136(tmp_path/'src/lib/data.ts').write_text("'Genesis': { code: 'gen'")137csvfile=tmp_path/'public/JapKougo.csv'138csvfile.write_text('Book,Chapter,Verse,Text\nGenesis,1,1,本文\nGenesis,1,1,本文\n')139with pytest.raises(ValueError,match='Invalid site reference'):load_site(tmp_path)140csvfile.write_text('Book,Chapter,Verse,Text\nGenesis,1,1,本文\n')141with pytest.raises(ValueError,match='complete'):load_site(tmp_path)142