Files
bid-doctor/server/tests/test_units.py
YANG JIANKUAN ad7fba6021 feat(server): 工程骨架后端——上传 → 解析 → 清单最小链路
- core:配置(prod 拒绝默认密钥 / dev 短信 / 假模型)、租户事务 + 行级安全策略、
  problem+json 错误码、信封加密与签名下载、对象存储、事务内入队、Valkey stream 事件流、权限点
- identity:手机号 HMAC 存储、注册、登录(挤下线需确认,API3)、服务端会话
- billing:额度流水只追加,预扣 / 结算 / 退回,一笔预扣只有一个结局
- document:分片上传、按文件头识别格式、Gotenberg 转换、文字层与稳定句子编号
- checklist:标注规则识别、模型抽取、三道校验、标注类条款规则兜底、重跑对齐
- ai:提示词注册表(extract.substantive v1 来自 S4 v2)、假模型、OpenAI 兼容供应商、ai_call 流水
- 迁移:data-model 基线、套餐、Procrastinate、会话状态函数
- 测试 30 个:租户隔离、额度、失败退回、对象加密、契约一致性
- Compose(含 migrate)、镜像、CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:48:10 +08:00

76 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""不需要数据库的单元测试:证据校验、格式识别、文字层。"""
from __future__ import annotations
import pytest
from bid_doctor.checklist.extract import check_basis, check_evidence, is_marked
from bid_doctor.core.errors import AppError
from bid_doctor.core.events import _sid # pyright: ignore[reportPrivateUsage]
from bid_doctor.document.formats import detect
from bid_doctor.document.pipeline.text_layer import Sentence, extract
from tests.conftest import FIXTURES
def sent(text: str, runs: list[tuple[int, int, str]] | None = None, seq: int = 1) -> Sentence:
return Sentence(key=f"d:p1:s{seq}", page_no=1, seq=seq, text=text, quads=[[0, 0, 1, 1]], fmt_runs=runs or [])
def test_evidence_checks() -> None:
s = sent("★投标人须具备有效的信息系统集成服务资质证书。")
by_id = {"p1s1": s}
assert check_evidence({"sid": "p1s1", "quote": "投标人须具备有效的信息"}, by_id) is None
assert check_evidence({"sid": "p9s9", "quote": "投标人须具备有效的信息"}, by_id) == "id"
assert check_evidence({"sid": "p1s1", "quote": "投标人须具备"}, by_id) == "quote" # 少于 8 个字
assert check_evidence({"sid": "p1s1", "quote": "这句话是模型改写的"}, by_id) == "quote"
def test_basis_check() -> None:
star = sent("★服务器内存不低于32GB。")
plain = sent("投标人应按要求提供售后服务方案。")
iu = sent("投标人须提供原厂授权书。", [(0, 12, "iu")])
assert check_basis("star", [star], [star], set())
assert not check_basis("star", [plain], [plain], set())
# 斜体下划线只在文件声明过时才算(07 F1)
assert not check_basis("italic_underline", [iu], [iu], set())
assert check_basis("italic_underline", [iu], [iu], {"italic_underline"})
invalid = sent("未提供的,其投标无效。", seq=2)
assert check_basis("explicit_invalid", [plain], [plain, invalid], set())
assert not check_basis("unknown", [star], [star], set())
def test_marker_fallback() -> None:
assert is_marked(sent("★采用国产化CPU芯片。"), set()) == "star"
iu = sent("投标人须提供原厂授权书。", [(0, 12, "iu")])
assert is_marked(iu, set()) is None
assert is_marked(iu, {"italic_underline"}) == "italic_underline"
def test_marked_text_for_model() -> None:
s = sent("须提供授权书,否则无效", [(3, 6, "iu"), (9, 11, "u")])
assert s.marked == "须提供<iu>授权书</iu>,否则<u>无效</u>"
def test_detect_formats() -> None:
pdf = (FIXTURES / "tender-mini.pdf").read_bytes()
d = detect(pdf, "采购文件.pdf")
assert (d.format, d.page_count, d.extension_mismatch) == ("pdf", 1, False)
assert detect(pdf, "采购文件.doc").extension_mismatch
with pytest.raises(AppError) as e:
detect(b"hello", "a.doc")
assert e.value.code == "file_format_unsupported"
def test_text_layer_normalizes_radicals_and_keys() -> None:
pages = extract("doc1", (FIXTURES / "tender-mini.pdf").read_bytes())
texts = [s.text for s in pages[0].sentences]
assert any("项目" in t for t in texts) and not any("⽬" in t for t in texts) # 「目」不是康熙部首
assert any("彩页" in t for t in texts)
keys = [s.key for s in pages[0].sentences]
assert keys[0] == "doc1:p1:s1" and len(set(keys)) == len(keys)
def test_stream_id_compare() -> None:
assert _sid("1700000000000-1") > _sid("999-5")
assert _sid("bad") == (0, 0)