import json import tempfile import time import unittest from pathlib import Path from PIL import Image import numpy as np from hud_alpha import clear_world_alpha, clear_supplemental_hud_alpha from run_bridge import (decode_state_line, translate_command, full_screen_capture, remove_enemy_hud, native_window_frame, remove_pause_overlay, FRAME_HEADER, raw_frame_bytes, FramePublisher) class BridgeTests(unittest.TestCase): def test_empty_native_drone_equipment_does_not_erase_weapons(self): weapons=[{'slot':0,'name':'MISSILES_2','title':'Artemis Missiles','ammo_cost':1}, {'slot':1,'name':'LASER_BURST_3','title':'Burst Laser Mark II','ammo_cost':0}] raw={'protocol':2,'source':'hyperspace','ready':True, 'player':{'weapons':weapons,'drone_equipment':{},'crew':{},'drones':{}}} normalized=decode_state_line('FTLVR_STATE '+json.dumps(raw)) self.assertEqual(normalized['player']['drone_equipment'],[]) self.assertEqual(normalized['player']['weapons'],weapons) def test_raw_transport_keeps_dimensions_rgba_orientation_and_timestamp(self): image=Image.new('RGBA',(960,540),(10,20,30,40)) image.putpixel((0,0),(1,2,3,4));image.putpixel((0,539),(5,6,7,8)) raw=raw_frame_bytes(image,12,123.5) self.assertEqual(FRAME_HEADER.size,36) self.assertEqual(FRAME_HEADER.unpack(raw[:36]),(b'FVR1',1,960,540,4,12,123.5)) self.assertEqual(len(raw),36+960*540*4) self.assertEqual(raw[36:40],bytes((1,2,3,4))) self.assertEqual(raw[36+539*960*4:40+539*960*4],bytes((5,6,7,8))) def test_independent_raw_streams_publish_without_waiting_for_png_preview(self): with tempfile.TemporaryDirectory() as directory: publisher=FramePublisher(Path(directory)) image=Image.new('RGBA',(16,9),(10,20,30,40)) try: for i in range(8):publisher.publish('screen_frame',image,float(i)) publisher.publish('hud_frame',image,8.) raw=(Path(directory)/'screen_frame.rgba').read_bytes() self.assertEqual(FRAME_HEADER.unpack(raw[:36])[-2:],(8,7.)) self.assertTrue((Path(directory)/'hud_frame.rgba').exists()) deadline=time.monotonic()+1 while not (Path(directory)/'hud_frame.png').exists() and time.monotonic()