"""`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 def test_bbox_to_window_mapping(): assert bbox_to_window([1, 2, 3, 4]) == { "min_x": 1.0, "min_y": 2.0, "max_x": 3.0, "max_y": 4.0, } 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 assert collect_frame(ctx, 1, {"bbox": None}) is None def test_collect_frame_returns_none_for_bad_bbox_length(): ctx = make_ctx(client=FakeMcpClient()) assert collect_frame(ctx, 1, {"bbox": [0, 0, 10]}) is None def build_evidence_client(image=ok_image("QUJD")): return FakeMcpClient( responses={ "query_entities": ok_text({"total": 5, "items": [{"handle": "A"}]}), "get_text_content": ok_text({"total": 1, "items": [{"text": "你好"}]}), "get_dimensions": ok_text({"total": 2, "items": []}), "get_block_references": ok_text({"total": 0, "items": []}), "get_polylines_info": ok_text({"total": 3, "items": []}), "get_viewport_screenshot": image, } ) def test_collect_frame_assembles_evidence(): ctx = make_ctx(client=build_evidence_client()) ev = collect_frame(ctx, 2, frame([0, 0, 100, 50])) assert ev["index"] == 2 assert ev["window"] == {"min_x": 0.0, "min_y": 0.0, "max_x": 100.0, "max_y": 50.0} assert ev["entities"]["total"] == 5 assert ev["texts"]["total"] == 1 assert ev["dimensions"]["total"] == 2 assert ev["blocks"]["total"] == 0 assert ev["polylines"]["total"] == 3 assert ev["image_b64"] == "QUJD" assert ev["image_mime"] == "image/png" def test_collect_frame_calls_expected_tools(): ctx = make_ctx(client=build_evidence_client(), frame_limit=99) collect_frame(ctx, 1, frame([1, 2, 3, 4])) client = ctx.client win = {"min_x": 1.0, "min_y": 2.0, "max_x": 3.0, "max_y": 4.0} assert client.arguments_of("zoom_to_window") == dict(win, margin=0.02) for name in ( "query_entities", "get_text_content", "get_dimensions", "get_block_references", "get_polylines_info", ): assert client.arguments_of(name) == {"window": win, "limit": 99} assert client.arguments_of("get_viewport_screenshot") == {} def test_collect_frame_without_image(): ctx = make_ctx(client=build_evidence_client(image=ok_text({}))) ev = collect_frame(ctx, 1, frame([0, 0, 10, 10])) assert ev["image_b64"] is None assert ev["image_mime"] is None def test_collect_frame_tolerates_empty_structured_data(): ctx = make_ctx(client=FakeMcpClient()) # 全部默认 ok_text({}) ev = collect_frame(ctx, 1, frame([0, 0, 10, 10])) assert ev["entities"] == {} assert ev["image_b64"] is None