221 lines
7.5 KiB
Python
221 lines
7.5 KiB
Python
import importlib.util
|
||
import json
|
||
import runpy
|
||
import sys
|
||
from pathlib import Path
|
||
from types import ModuleType
|
||
|
||
import pytest
|
||
|
||
|
||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||
SPEC_CHECKER_PATH = (
|
||
REPO_ROOT / "skills" / "gaokao-spec-checker" / "scripts" / "spec_checker_v2.py"
|
||
)
|
||
VISUAL_REPORT_PATH = (
|
||
REPO_ROOT
|
||
/ "skills"
|
||
/ "gaokao-college-advisor"
|
||
/ "scripts"
|
||
/ "gaokao_visual_report.py"
|
||
)
|
||
|
||
|
||
def _load_module(name: str, path: Path) -> ModuleType:
|
||
spec = importlib.util.spec_from_file_location(name, path)
|
||
assert spec is not None and spec.loader is not None
|
||
module = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(module)
|
||
return module
|
||
|
||
|
||
spec_checker = _load_module("spec_checker_v2_coverage", SPEC_CHECKER_PATH)
|
||
visual_report = _load_module("gaokao_visual_report_coverage", VISUAL_REPORT_PATH)
|
||
|
||
|
||
GaokaoSpecCheckerV2 = spec_checker.GaokaoSpecCheckerV2
|
||
|
||
|
||
def test_detect_province_alias_branch():
|
||
assert spec_checker.detect_province("湘考生,578分,志愿方案") == "湖南"
|
||
|
||
|
||
def test_detect_province_full_name_branch(monkeypatch):
|
||
trimmed_rules = dict(spec_checker.PROVINCE_RULES)
|
||
trimmed_rules.pop("广东")
|
||
monkeypatch.setattr(spec_checker, "PROVINCE_RULES", trimmed_rules)
|
||
assert spec_checker.detect_province("广东省考生,630分,志愿方案") == "广东"
|
||
|
||
|
||
def test_report_unsupported_province_branch():
|
||
checker = GaokaoSpecCheckerV2(province="火星")
|
||
report = checker.auto_detect_and_check("火星考生志愿方案")
|
||
assert "暂不支持 火星" in report
|
||
|
||
|
||
def test_checker_hits_core_warning_and_validation_branches():
|
||
checker = GaokaoSpecCheckerV2(province="湖南")
|
||
report = checker.auto_detect_and_check(
|
||
"\n".join([
|
||
"湖南2026高考志愿填报方案",
|
||
"本次共填报20个院校专业组志愿。",
|
||
"每组最多6个专业。",
|
||
"全部专业服从调剂。",
|
||
"会计专业普遍要求物化生。",
|
||
"88%录取概率。",
|
||
"2026年位次预计5000名。",
|
||
"请关注退档风险。",
|
||
])
|
||
)
|
||
assert "调剂范围错误(湖南)" in report
|
||
assert "主观概率估算" in report
|
||
assert "2026年位次" in report
|
||
assert "选科要求一刀切" in report
|
||
|
||
|
||
def test_checker_hits_professional_school_mode_error():
|
||
checker = GaokaoSpecCheckerV2(province="浙江")
|
||
report = checker.auto_detect_and_check(
|
||
"\n".join([
|
||
"浙江省630分志愿方案",
|
||
"本次共填报80个专业+学校志愿。",
|
||
"每个志愿填1个专业。",
|
||
"仍保留专业组概念,并支持组内调剂。",
|
||
"风险提示:注意退档风险。",
|
||
])
|
||
)
|
||
assert "模式错误(浙江)" in report
|
||
|
||
|
||
def test_checker_can_generate_clean_report():
|
||
checker = GaokaoSpecCheckerV2(province="浙江")
|
||
report = checker.auto_detect_and_check(
|
||
"\n".join([
|
||
"浙江省630分志愿方案",
|
||
"本次共填报80个专业+学校志愿。",
|
||
"每个志愿填1个专业。",
|
||
"无调剂。",
|
||
"风险提示:注意退档与体检限制。",
|
||
])
|
||
)
|
||
assert "方案基本合规" in report
|
||
assert "问题总数:0 个" in report
|
||
|
||
|
||
def test_checker_hits_volunteer_overflow_branch():
|
||
checker = GaokaoSpecCheckerV2(province="湖南")
|
||
report = checker.auto_detect_and_check(
|
||
"\n".join([
|
||
"湖南2026高考志愿填报方案",
|
||
"本次共填报46个院校专业组志愿。",
|
||
"每组最多6个专业。",
|
||
"组内专业服从调剂。",
|
||
"风险提示:注意退档风险。",
|
||
])
|
||
)
|
||
assert "志愿数量超标(湖南)" in report
|
||
|
||
|
||
def test_spec_checker_main_without_args_runs_demo_output(capsys, monkeypatch):
|
||
monkeypatch.setattr(sys, "argv", [str(SPEC_CHECKER_PATH)])
|
||
runpy.run_path(str(SPEC_CHECKER_PATH), run_name="__main__")
|
||
output = capsys.readouterr().out
|
||
assert "测试1:湖南方案(错误版)" in output
|
||
assert "测试2:浙江方案(专业+学校模式)" in output
|
||
assert "测试3:山东方案" in output
|
||
|
||
|
||
def test_spec_checker_main_with_file_argument_outputs_report(
|
||
tmp_path, capsys, monkeypatch
|
||
):
|
||
plan_path = tmp_path / "plan.txt"
|
||
plan_path.write_text(
|
||
"湖南考生,578分,志愿方案\n每组最多6个专业。\n风险提示:注意退档风险。",
|
||
encoding="utf-8",
|
||
)
|
||
monkeypatch.setattr(sys, "argv", [str(SPEC_CHECKER_PATH), str(plan_path), "湖南"])
|
||
runpy.run_path(str(SPEC_CHECKER_PATH), run_name="__main__")
|
||
output = capsys.readouterr().out
|
||
assert "志愿方案规范检查报告" in output
|
||
assert "检测省份:湖南" in output
|
||
|
||
|
||
def test_visual_report_usage_message(capsys, monkeypatch):
|
||
monkeypatch.setattr(visual_report.sys, "argv", ["gaokao_visual_report.py"])
|
||
with pytest.raises(SystemExit) as exc:
|
||
visual_report.main()
|
||
assert exc.value.code == 1
|
||
output = capsys.readouterr().out
|
||
assert "用法: python3 gaokao_visual_report.py <student_data.json>" in output
|
||
assert "生成示例" in output
|
||
|
||
|
||
def test_visual_report_demo_mode(capsys, monkeypatch):
|
||
monkeypatch.setattr(
|
||
visual_report,
|
||
"generate_visual_report",
|
||
lambda student, volunteers, output_format="all": ["/tmp/demo.md"],
|
||
)
|
||
monkeypatch.setattr(
|
||
visual_report.sys, "argv", ["gaokao_visual_report.py", "--demo"]
|
||
)
|
||
|
||
visual_report.main()
|
||
|
||
output = capsys.readouterr().out
|
||
assert "生成完成" in output
|
||
assert "/tmp/demo.md" in output
|
||
|
||
|
||
def test_visual_report_json_input(tmp_path, capsys, monkeypatch):
|
||
payload = {
|
||
"student": {"name": "张三", "province": "浙江省", "score": 620},
|
||
"volunteers": [{"school": "浙江大学", "major": "计算机类"}],
|
||
}
|
||
data_path = tmp_path / "student.json"
|
||
data_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
|
||
|
||
observed: dict[str, object] = {}
|
||
|
||
def fake_generate(student, volunteers, output_format="all"):
|
||
observed["student"] = student
|
||
observed["volunteers"] = volunteers
|
||
observed["output_format"] = output_format
|
||
return ["/tmp/from-json.html"]
|
||
|
||
monkeypatch.setattr(visual_report, "generate_visual_report", fake_generate)
|
||
monkeypatch.setattr(
|
||
visual_report.sys, "argv", ["gaokao_visual_report.py", str(data_path)]
|
||
)
|
||
|
||
visual_report.main()
|
||
|
||
assert observed["student"] == payload["student"]
|
||
assert observed["volunteers"] == payload["volunteers"]
|
||
assert observed["output_format"] == "all"
|
||
output = capsys.readouterr().out
|
||
assert "/tmp/from-json.html" in output
|
||
|
||
|
||
def test_visual_report_main_guard_executes_script(tmp_path, capsys, monkeypatch):
|
||
payload = {
|
||
"student": {"name": "张三", "province": "浙江省", "score": 620},
|
||
"volunteers": [
|
||
{
|
||
"school": "浙江大学",
|
||
"major": "计算机类",
|
||
"match_score": 95,
|
||
"type": "稳",
|
||
"probability": 70,
|
||
"required_subjects": ["数学", "physical"],
|
||
}
|
||
],
|
||
}
|
||
data_path = tmp_path / "student.json"
|
||
data_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
|
||
monkeypatch.chdir(tmp_path)
|
||
monkeypatch.setattr(sys, "argv", [str(VISUAL_REPORT_PATH), str(data_path)])
|
||
runpy.run_path(str(VISUAL_REPORT_PATH), run_name="__main__")
|
||
output = capsys.readouterr().out
|
||
assert "生成完成" in output
|