Files
2026-08-03 18:42:47 +08:00

163 lines
5.8 KiB
Python
Executable File

import base64
import tempfile
import unittest
from html.parser import HTMLParser
from pathlib import Path
from build_dual_html import (
EXPERIMENT_OUTPUT,
MANUSCRIPT_OUTPUT,
ROOT,
build_experiment_plan,
build_manuscript_reader,
document_shell,
figure_card,
image_data_uri,
inline_markup,
markdown_blocks,
markdown_table,
)
class CountingParser(HTMLParser):
def __init__(self):
super().__init__()
self.ids = []
self.images = 0
self.tables = 0
def handle_starttag(self, tag, attrs):
values = dict(attrs)
if "id" in values:
self.ids.append(values["id"])
if tag == "img":
self.images += 1
if tag == "table":
self.tables += 1
class MarkdownPrimitiveTests(unittest.TestCase):
def test_inline_markup_escapes_and_formats(self):
source = "**PlantAI** uses `Manifest` & [AIIA](https://example.org)."
rendered = inline_markup(source)
self.assertIn("<strong>PlantAI</strong>", rendered)
self.assertIn("<code>Manifest</code>", rendered)
self.assertIn("&amp;", rendered)
self.assertIn('href="https://example.org"', rendered)
def test_markdown_table_is_semantic(self):
source = "| A | B |\n|---|---|\n| x | y |\n"
rendered = markdown_table(source)
self.assertIn("<thead>", rendered)
self.assertIn("<tbody>", rendered)
self.assertIn("<th>A</th>", rendered)
self.assertIn("<td>y</td>", rendered)
def test_markdown_blocks_supports_heading_list_quote_and_paragraph(self):
source = "## 标题\n\n> 提示\n\n- 项目一\n- 项目二\n\n正文。\n"
rendered = markdown_blocks(source)
self.assertIn("<h2", rendered)
self.assertIn("<blockquote>", rendered)
self.assertIn("<ul>", rendered)
self.assertIn("<p>正文。</p>", rendered)
def test_png_is_embedded_as_data_uri(self):
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "plot.png"
payload = b"\x89PNG\r\n\x1a\nexample"
path.write_bytes(payload)
uri = image_data_uri(path)
self.assertEqual(
uri,
"data:image/png;base64," + base64.b64encode(payload).decode("ascii"),
)
class ManuscriptReaderTests(unittest.TestCase):
def test_document_shell_is_standalone(self):
page = document_shell(
"T", "E", "S", ["P"], [("x", "X")], ['<section id="x">X</section>']
)
self.assertIn("<!doctype html>", page.lower())
self.assertIn("@media print", page)
self.assertNotRegex(page, r'<(?:link|script)[^>]+(?:href|src)="https?://')
def test_simulated_figure_card_has_visible_warning(self):
png = ROOT / "figures/exports/figure2_rnaseq_scenarios_SIMULATED.png"
card = figure_card(2, "RNA-seq", "caption", png, True)
self.assertIn("SIMULATED DATA — DRAFT ONLY", card)
self.assertIn("data:image/png;base64,", card)
def test_manuscript_reader_contains_five_figures_and_three_tables(self):
page = build_manuscript_reader()
parser = CountingParser()
parser.feed(page)
self.assertEqual(parser.images, 5)
self.assertGreaterEqual(parser.tables, 3)
self.assertIn("PlantAI-dev", page)
self.assertIn("PlantAI-RAG", page)
self.assertGreaterEqual(page.count("SIMULATED DATA — DRAFT ONLY"), 8)
class ExperimentPlanTests(unittest.TestCase):
def test_experiment_plan_has_17_numbered_sections_and_all_assets(self):
page = build_experiment_plan()
parser = CountingParser()
parser.feed(page)
for number in range(17):
self.assertIn(f'id="plan-{number}"', page)
self.assertEqual(parser.images, 5)
self.assertGreaterEqual(parser.tables, 3)
self.assertGreaterEqual(page.count("SIMULATED DATA — DRAFT ONLY"), 8)
def test_experiment_plan_contains_five_experiments_and_reviewer_views(self):
page = build_experiment_plan()
for phrase in (
"系统级可执行闭环",
"多场景RNA-seq",
"RNA-seq到候选家族",
"轻量Extension",
"Graph RAG",
"审稿人视角",
"生信分析师视角",
"智能体工程师视角",
):
self.assertIn(phrase, page)
def test_experiment_plan_does_not_claim_excluded_capabilities(self):
page = build_experiment_plan()
self.assertIn("Diagnosis Agent不纳入论文贡献", page)
self.assertIn("agentic RAG未进入当前主路径", page)
self.assertIn("重测序—GWAS仅作为后续方向", page)
class OutputIntegrityTests(unittest.TestCase):
def test_both_outputs_are_self_contained_and_parseable(self):
for path in (MANUSCRIPT_OUTPUT, EXPERIMENT_OUTPUT):
page = path.read_text(encoding="utf-8")
parser = CountingParser()
parser.feed(page)
self.assertEqual(parser.images, 5)
self.assertEqual(len(parser.ids), len(set(parser.ids)))
self.assertNotIn("file://", page)
self.assertNotRegex(page, r'<img[^>]+src=["\'](?:/|https?://)')
self.assertNotRegex(page, r"\{\{[A-Z_][A-Z0-9_]*\}\}")
self.assertIn("@media print", page)
def test_required_terms_and_simulation_labels_are_present(self):
for path in (MANUSCRIPT_OUTPUT, EXPERIMENT_OUTPUT):
page = path.read_text(encoding="utf-8")
for term in (
"Artificial Intelligence in Agriculture",
"PlantAI-dev",
"PlantAI-RAG",
"Graph RAG",
"Extension",
"SIMULATED DATA — DRAFT ONLY",
):
self.assertIn(term, page)
if __name__ == "__main__":
unittest.main()