test(review): 把 5 处既有瑕疵锁成 *_known_gap 用例

让既有瑕疵可见,而不是被当成正确行为;改 1~3(确定性检查前置/结论结构化/
证据交叉校验)时可据此判断行为是否被改变。

- bbox_to_window 含非数值 → ValueError(上游只判长度)
- summarize / extract_issues 硬下标 f['frame'] → KeyError
- annotate 的 created 无去重(同 handle 产生重复批注)
- extract_issues 单行 ```json[...]``` 围栏剥离失败 → []
- result_json 文本 'null' → None(与「无 text 返回 default」语义易混)
This commit is contained in:
gjm committed 2026-10-14 19:09:56 +08:00
1 parent fa2d01aad2
commit daccc734bf
4 files changed
+51

No files matched your search

+15
View File
@@ -120,6 +120,21 @@ def test_annotate_handles_multiple_created_entities():
assert created == ["N1", "N2"]
def test_annotate_created_not_deduped_known_gap():
"""已知瑕疵:同一 handle 出现两次会创建两条批注(created 无去重,仅 highlighted 去重)。"""
ctx = make_ctx(client=build_client())
created, highlighted = annotate(
ctx,
[
{"handle": "A", "severity": "high", "message": "第一次"},
{"handle": "A", "severity": "high", "message": "第二次"},
],
log=lambda *a: None,
)
assert created == ["NEW1", "NEW1"] # 重复批注(期望去重)
assert highlighted == ["A"] # 高亮已去重
def test_annotate_propagates_protocol_error_on_detail():
ctx = make_ctx(client=FakeMcpClient(responses={"get_entity_detail": McpError(-32602, "bad")}))
# annotate 只兜 add_leader/highlight 的错;detail 的协议错误会向上冒泡(现状行为)
+8
View File
@@ -1,5 +1,7 @@
"""`dwg_review.phases.evidence` 单元测试。"""
import pytest
from dwg_review.phases.evidence import bbox_to_window, collect_frame
from tests.fakes import FakeMcpClient, frame, make_ctx, ok_image, ok_text
@@ -13,6 +15,12 @@ def test_bbox_to_window_mapping():
}
def test_bbox_to_window_non_numeric_known_gap():
"""已知瑕疵:4 元素但含非数值的 bbox 会抛 ValueError,上游 collect_frame 只判长度。"""
with pytest.raises(ValueError):
bbox_to_window([0, "a", 10, 10])
def test_collect_frame_returns_none_for_missing_bbox():
ctx = make_ctx(client=FakeMcpClient())
assert collect_frame(ctx, 1, {}) is None
+5
View File
@@ -63,6 +63,11 @@ def test_result_json_returns_default_when_no_text():
assert result_json(None, "D") == "D"
def test_result_json_null_text_known_gap():
"""已知瑕疵:文本 'null' 是合法 JSON,解析为 None,与「无 text 返回 default」语义易混。"""
assert result_json(ok_text("null"), "D") is None
def test_result_texts_tolerates_malformed_response():
assert result_texts(None) == []
assert result_texts({}) == []
+23
View File
@@ -2,6 +2,8 @@
import json
import pytest
from dwg_review.phases.report import extract_issues, save_report, summarize
from tests.fakes import FakeLlmClient, make_ctx
@@ -44,6 +46,13 @@ def test_summarize_falls_back_to_raw_input_on_error():
assert any("汇总失败" in line for line in logs)
def test_summarize_missing_frame_key_known_gap():
"""已知瑕疵:summarize 用硬下标 f['frame'],findings 缺该键直接 KeyError。"""
ctx = make_ctx(llm=FakeLlmClient(text="x"))
with pytest.raises(KeyError):
summarize(ctx, [{"finding": "缺 frame 键"}], log=lambda *a: None)
# ---------------------------------------------------------------------------
# extract_issues
# ---------------------------------------------------------------------------
@@ -85,6 +94,20 @@ def test_extract_issues_returns_empty_when_not_a_list():
assert extract_issues(ctx, findings_fixture(), log=lambda *a: None) == []
def test_extract_issues_single_line_fence_known_gap():
"""已知瑕疵:围栏剥离依赖换行,单行 ```json[...]``` 会残留 json 前缀 → 解析失败。"""
llm = FakeLlmClient(text_script=['```json[{"frame": 1, "message": "z"}]```'])
ctx = make_ctx(llm=llm)
assert extract_issues(ctx, findings_fixture(), log=lambda *a: None) == []
def test_extract_issues_missing_frame_key_known_gap():
"""已知瑕疵:extract_issues 同样用硬下标 f['frame'],findings 缺该键直接 KeyError。"""
ctx = make_ctx(llm=FakeLlmClient(text="[]"))
with pytest.raises(KeyError):
extract_issues(ctx, [{"finding": "缺 frame 键"}], log=lambda *a: None)
# ---------------------------------------------------------------------------
# save_report
# ---------------------------------------------------------------------------