import math import socket import struct import sys import unittest from pathlib import Path from unittest.mock import Mock, patch PROJECT_ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(PROJECT_ROOT)) from error_output import ( ErrorOutputSender, build_error_payload, decode_guidance_v1_response, encode_error_payload, ) class ErrorOutputTests(unittest.TestCase): def test_pixel_units_from_normalized_guidance_error(self): payload = build_error_payload( {"frame_id": 7, "frame_w": 1280, "frame_h": 720, "error_x": 0.25, "error_y": -0.5}, units="px", timestamp=1.0, ) self.assertEqual(payload["unit"], "px") self.assertEqual(payload["x"], 160.0) self.assertEqual(payload["y"], -180.0) self.assertAlmostEqual(payload["mag"], math.hypot(160.0, -180.0)) def test_degree_units_use_fov(self): payload = build_error_payload( {"frame_w": 100, "frame_h": 100, "error_x": 1.0, "error_y": 0.0}, units="deg", hfov_deg=90, vfov_deg=60, timestamp=1.0, ) self.assertEqual(payload["unit"], "deg") self.assertAlmostEqual(payload["x"], 45.0, places=5) self.assertAlmostEqual(payload["y"], 0.0, places=5) def test_meter_units_need_range(self): payload = build_error_payload( {"frame_w": 100, "frame_h": 100, "error_x": 1.0, "error_y": 0.0}, units="m", hfov_deg=90, range_m=10, timestamp=1.0, ) self.assertTrue(payload["valid"]) self.assertAlmostEqual(payload["x"], 10.0, places=5) def test_binary_packet_magic(self): payload = build_error_payload({"frame_id": 3, "frame_w": 100, "frame_h": 100}, timestamp=1.0) data = encode_error_payload(payload, "bin") self.assertEqual(data[:4], b"FPVE") self.assertEqual(struct.unpack("