diff --git a/tests/test_annotator.py b/tests/test_annotator.py index 1240316..46dbe3a 100644 --- a/tests/test_annotator.py +++ b/tests/test_annotator.py @@ -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 的协议错误会向上冒泡(现状行为) diff --git a/tests/test_evidence.py b/tests/test_evidence.py index fe498cf..1964a3d 100644 --- a/tests/test_evidence.py +++ b/tests/test_evidence.py @@ -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 diff --git a/tests/test_mcp_client.py b/tests/test_mcp_client.py index feefb82..1287d60 100644 --- a/tests/test_mcp_client.py +++ b/tests/test_mcp_client.py @@ -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({}) == [] diff --git a/tests/test_report.py b/tests/test_report.py index 7111071..aaa17c1 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -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 # ---------------------------------------------------------------------------