import pytest from PySide6.QtWidgets import QMainWindow from hookvision.models import HookState, Config from hookvision.main_window_v2 import MainWindow from hookvision.config_loader import load_config class TestParseAIObjects: def test_none_payload(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) assert mw.parse_ai_objects(None, 640, 360) == [] assert mw.parse_ai_objects({}, 640, 360) == [] def test_empty_objects(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) result = mw.parse_ai_objects({"width": 640, "height": 360, "objects": []}, 640, 360) assert result == [] def test_valid_objects(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 640, "height": 360, "objects": [ "0|100|200|50|80|hoist", "0|300|150|40|60|cup", ] } result = mw.parse_ai_objects(payload, 640, 360) assert len(result) == 2 assert result[0]["label"] == "hook" assert result[0]["x"] == 100 assert result[0]["y"] == 200 assert result[0]["color"] == (0, 0, 255) assert result[1]["label"] == "lug" assert result[1]["color"] == (255, 0, 0) def test_scale_transformation(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 320, "height": 180, "objects": ["0|50|50|100|100|hoist"], } result = mw.parse_ai_objects(payload, 640, 360) assert result[0]["x"] == 100 assert result[0]["y"] == 100 assert result[0]["w"] == 200 assert result[0]["h"] == 200 def test_ready_object_excluded(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 640, "height": 360, "objects": [ "0|100|200|50|80|hoist", "0|300|150|40|60|ready", ] } result = mw.parse_ai_objects(payload, 640, 360, include_ready=False) assert len(result) == 1 assert result[0]["label"] == "hook" def test_ready_object_included(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 640, "height": 360, "objects": [ "0|100|200|50|80|ready", ] } result = mw.parse_ai_objects(payload, 640, 360, include_ready=True) assert len(result) == 1 assert "ready" in result[0]["label"] def test_malformed_objects_skipped(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 640, "height": 360, "objects": [ "not_enough_parts", "0|abc|def|ghi|jkl|hoist", "0|100|200|50|80|hoist", ] } result = mw.parse_ai_objects(payload, 640, 360) assert len(result) == 1 def test_zero_orig_size_no_division_error(self, qapp, sample_config_path): config = load_config(sample_config_path) mw = MainWindow(config) payload = { "width": 0, "height": 0, "objects": ["0|100|200|50|80|hoist"], } result = mw.parse_ai_objects(payload, 640, 360) assert len(result) == 1 assert result[0]["x"] == 100 assert result[0]["y"] == 200 class TestRectsIntersect: def setup_method(self): self.mw = MainWindow(Config()) def test_overlapping(self, qapp): mw = MainWindow(Config()) a = {"x": 0, "y": 0, "w": 100, "h": 100} b = {"x": 50, "y": 50, "w": 100, "h": 100} assert mw.rects_intersect(a, b) is True def test_non_overlapping(self, qapp): mw = MainWindow(Config()) a = {"x": 0, "y": 0, "w": 50, "h": 50} b = {"x": 100, "y": 100, "w": 50, "h": 50} assert mw.rects_intersect(a, b) is False def test_touching_edge_intersecting(self, qapp): mw = MainWindow(Config()) a = {"x": 0, "y": 0, "w": 50, "h": 50} b = {"x": 50, "y": 0, "w": 50, "h": 50} # 边沿相接触视为相交(用于挂钩/吊耳判定的宽松策略) assert mw.rects_intersect(a, b) is True def test_one_contains_other(self, qapp): mw = MainWindow(Config()) a = {"x": 0, "y": 0, "w": 200, "h": 200} b = {"x": 50, "y": 50, "w": 50, "h": 50} assert mw.rects_intersect(a, b) is True class TestHasIntersectingPair: def test_no_pairs(self, qapp): mw = MainWindow(Config()) assert mw._has_intersecting_pair(None, None) is False def test_left_pair_intersects(self, qapp): mw = MainWindow(Config()) left_pair = ( {"x": 0, "y": 0, "w": 100, "h": 100}, {"x": 50, "y": 50, "w": 100, "h": 100}, ) assert mw._has_intersecting_pair(left_pair, None) is True def test_right_pair_intersects(self, qapp): mw = MainWindow(Config()) right_pair = ( {"x": 0, "y": 0, "w": 100, "h": 100}, {"x": 50, "y": 50, "w": 100, "h": 100}, ) assert mw._has_intersecting_pair(None, right_pair) is True def test_pair_not_intersecting(self, qapp): mw = MainWindow(Config()) pair = ( {"x": 0, "y": 0, "w": 50, "h": 50}, {"x": 100, "y": 100, "w": 50, "h": 50}, ) assert mw._has_intersecting_pair(pair, None) is False