Files
Jyotisha/tests/test_full_data_parity_chapters.py
T

260 lines
11 KiB
Python

"""Six parity chapters for issue #91 section A.
C-class sections stay absent. Labels are bilingual. Narayana's two methods
are separate headings. Fictional charts only.
"""
from __future__ import annotations
import copy
import re
import pytest
from scripts.pl9_full_data_export import render_full_data_markdown
from scripts.pl9_reader_english import HAN
from scripts.professional_report_reference import _english_edition
from scripts.report_render.appendix_language import chinese_prose_gates
from scripts.report_render.parity_chapters import (
CHAPTERS,
FORBIDDEN_TITLES,
LABELS,
SECTIONS,
_chapter_sections,
lab,
render_parity_chapters,
)
from tests.report_english_fictional import _load_packet
_SNAKE = re.compile(r"[A-Za-z][A-Za-z0-9]*_[A-Za-z0-9_]+")
_KAAL_ZH = re.compile(r"\d+ 颗中 \d+ 颗")
_KAAL_EN = re.compile(r"\d+ of \d+")
def _chapter_text(markdown: str, language: str) -> str:
marker = "# 大运附表" if language == "zh" else "# Dasha Appendix"
assert marker in markdown
return markdown.split(marker, 1)[1]
def _section_body(markdown: str, heading: str) -> str:
marker = f"## {heading}"
start = markdown.index(marker) + len(marker)
rest = markdown[start:]
ends = [pos for pos in (rest.find("\n## "), rest.find("\n# ")) if pos >= 0]
return rest[: min(ends)] if ends else rest
def test_chapter_titles_follow_the_task_groups() -> None:
groups = _chapter_sections()
assert len(groups) == len(CHAPTERS) == 6
assert [title for group in groups for title in group] == [title for title, _zh in SECTIONS]
for (chapter_en, chapter_zh), titles in zip(CHAPTERS, groups):
assert chapter_en and chapter_zh
assert titles
def test_labels_cover_both_languages_and_a_missing_label_fails() -> None:
for key, pair in LABELS.items():
assert pair[0] and pair[1], key
assert lab(key, "en") == pair[0]
assert lab(key, "zh") == pair[1]
assert "_" not in pair[0] and "_" not in pair[1]
with pytest.raises(KeyError):
lab("not_a_real_column", "zh")
def test_empty_packet_chapters_are_headed_and_do_not_print_raw_keys() -> None:
for language in ("zh", "en"):
text = render_parity_chapters({}, language)
titles = SECTIONS
cursor = 0
for title_en, title_zh in titles:
heading = title_zh if language == "zh" else title_en
body = _section_body(text, heading)
assert body.strip(), heading
cursor_next = text.index(f"## {heading}", cursor)
assert cursor_next >= cursor
cursor = cursor_next
if "|---|" in body or "| --- |" in body:
lines = [line for line in body.splitlines() if line.startswith("|")]
assert len(lines) >= 3, heading
for title in FORBIDDEN_TITLES:
assert f"## {title}" not in text
assert f"# {title}" not in text
assert _SNAKE.search(text) is None
zh = render_parity_chapters({}, "zh")
en = render_parity_chapters({}, "en")
assert zh.index("### 来源感知口径") < zh.index("### 既有口径")
assert "来源感知口径" not in zh.split("### 既有口径", 1)[1]
assert en.index("### Source-aware method") < en.index("### Legacy method")
assert "Source-aware method" not in en.split("### Legacy method", 1)[1]
assert "印刷页 10" in zh
assert "printed pages 10-17" in en
for banned in ("source_locator", "profile_id", "niryaana_shoola_strength", "source_discrepancy", "sign_idx"):
assert banned not in zh
assert banned not in en
@pytest.fixture(scope="module")
def fictional_reports() -> dict[int, tuple[str, str]]:
reports = {}
for index in (0, 1, 9):
packet = _load_packet(index)
edition = _english_edition(packet, True)
chinese = render_full_data_markdown(packet)
english = edition.get("markdown_en") or ""
assert edition.get("english_unavailable") in (None, "")
assert english
reports[index] = (chinese, english)
return reports
def test_three_fictional_charts_render_the_same_chapters(fictional_reports: dict[int, tuple[str, str]]) -> None:
for index, (chinese, english) in fictional_reports.items():
assert chinese_prose_gates(chinese) == {"english_signs": 0, "han_function_glue": 0}
assert HAN.findall(english) == []
assert "[translation missing:" not in english
zh = _chapter_text(chinese, "zh")
en = _chapter_text(english, "en")
zh_at = 0
en_at = 0
for title_en, title_zh in SECTIONS:
zh_at = zh.index(f"## {title_zh}", zh_at)
en_at = en.index(f"## {title_en}", en_at)
for body, heading in ((_section_body(zh, title_zh), title_zh), (_section_body(en, title_en), title_en)):
assert body.strip(), f"{index} {heading}"
for chapter_en, chapter_zh in CHAPTERS:
assert chinese.count(f"# {chapter_zh}") == 1
assert english.count(f"# {chapter_en}") == 1
for title in FORBIDDEN_TITLES:
assert title not in zh
assert title not in en
assert _SNAKE.search(zh) is None
assert _SNAKE.search(en) is None
assert "印刷页 10" in zh and "printed pages 10-17" in en
assert "### 来源感知口径" in zh and "### 既有口径" in zh
assert "### Source-aware method" in en and "### Legacy method" in en
assert "再小运" in _section_body(zh, "Chara 大运时长")
assert "Pratyantardasha" in _section_body(en, "Chara Dasha Period Durations")
assert "marriage_windows" not in _section_body(zh, "Bhrigu 近似推进序列")
assert "venus_encounter" not in _section_body(en, "Bhrigu Approximate Progression")
assert "Raja Yoga" not in zh
assert "blocked" not in zh.lower()
_UNDETERMINED = {"zh": "未判定", "en": "Not determined"}
_GAP_LINE = {
"zh": "公开报告资料包未带此模块",
"en": "This module is not in the public report packet",
}
# These four modules are absent from the public worksheet. The reason is why
# the section may stay undetermined. Anything else must show a real cell.
_PACKET_GAPS = {
"Navamsha AD Duration": "navamsha_dasha is computed on the reading but is not copied into the public worksheet",
"Pancha Pakshi": "pancha_pakshi is not copied into the public worksheet",
"Rashi Tulya Navamsa": "rashi_tulya_navamsa is not copied into the public worksheet",
"Current Dasha Convergence": "dasa_convergence per-domain rows are not copied into the public worksheet",
}
def _table_blocks(body: str) -> list[list[list[str]]]:
blocks = []
current: list[str] = []
for line in body.splitlines():
if line.startswith("|"):
current.append(line)
continue
if current:
blocks.append(current)
current = []
if current:
blocks.append(current)
parsed = []
for block in blocks:
rows = []
for index, line in enumerate(block):
cells = [cell.strip() for cell in line.strip().strip("|").split("|")]
if cells and all(set(cell) <= set("-: ") and cell for cell in cells):
continue
if index == 0:
continue
rows.append(cells)
parsed.append(rows)
return parsed
def _section_has_real_cell(body: str, undetermined: str) -> bool:
blocks = _table_blocks(body)
if blocks:
return any(
cell and cell != undetermined
for rows in blocks
for row in rows
for cell in row
)
prose = [line.strip() for line in body.splitlines() if line.strip()]
return any(line and line != undetermined for line in prose)
def test_every_section_has_a_real_cell_except_the_four_public_gaps(fictional_reports: dict[int, tuple[str, str]]) -> None:
titles = dict(SECTIONS)
for reason in _PACKET_GAPS.values():
assert reason
for index, (chinese, english) in fictional_reports.items():
for language, markdown in (("zh", chinese), ("en", english)):
chapter = _chapter_text(markdown, language)
for title_en, title_zh in SECTIONS:
heading = title_zh if language == "zh" else title_en
body = _section_body(chapter, heading)
if title_en in _PACKET_GAPS:
first = next(line.strip() for line in body.splitlines() if line.strip())
assert first == _GAP_LINE[language], f"{index} {heading}"
continue
assert _section_has_real_cell(body, _UNDETERMINED[language]), f"{index} {heading}"
def test_parity_chapters_go_through_local_conventions() -> None:
from scripts.pl9_full_data_export import _apply_local_report_conventions
packet = {
"report_language": "zh",
"worksheets": {
"strengths_and_scores": {
"vimsopaka": {
"Sun": {"planet": "Sun", "total_score": 12.5, "category": "必然"},
}
}
},
}
chinese = render_full_data_markdown(packet)
zh_body = _section_body(chinese, "Vimsopaka 分盘贡献")
zh_replaced = _apply_local_report_conventions("必然", language="zh")
assert zh_replaced == "可能"
assert zh_replaced in zh_body
assert "必然" not in zh_body
english_packet = copy.deepcopy(packet)
english_packet["report_language"] = "en"
english_packet["worksheets"]["strengths_and_scores"]["vimsopaka"]["Sun"]["category"] = "divorce"
english = render_full_data_markdown(english_packet)
en_body = _section_body(english, "Vimsopaka Contribution")
en_replaced = _apply_local_report_conventions("divorce", language="en")
assert en_replaced == "relationship strain"
assert en_replaced in en_body
assert "divorce" not in en_body.lower()
def test_chart_nine_partial_kaal_and_friendship(fictional_reports: dict[int, tuple[str, str]]) -> None:
chinese, english = fictional_reports[9]
assert _KAAL_ZH.search(chinese)
assert _KAAL_EN.search(english)
zh_friends = _section_body(_chapter_text(chinese, "zh"), "行星中性与复合友敌关系")
en_friends = _section_body(_chapter_text(english, "en"), "Neutral and Compound Relationships")
zh_rows = [line for line in zh_friends.splitlines() if line.startswith("| 太阳") or line.startswith("| 月亮") or line.startswith("| 水星")]
assert len([line for line in zh_friends.splitlines() if line.startswith("| ") and "---" not in line]) >= 10
assert zh_rows
assert "极友" in zh_friends
assert "Great friend" in en_friends
assert "没有大运或小运交界" in chinese or "距参考日天数" in _section_body(_chapter_text(chinese, "zh"), "大运与小运交界检查")