71 lines
3.8 KiB
Python
71 lines
3.8 KiB
Python
"""Behavior tests for CAN validity and upstream per-door evidence gating."""
|
|
import sys
|
|
import unittest
|
|
import tempfile
|
|
from pathlib import Path
|
|
import numpy as np
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0,str(ROOT))
|
|
from run_camera import select_active_door,gate_risks,JsonlWriter
|
|
from door_mask_risk import DoorMaskSequence,DoorRiskEvaluator
|
|
from door_zone_risk import DoorZoneConfig,DoorZoneAssigner
|
|
from predict_optimized_pose_videos import BoxTracker
|
|
|
|
class CanTests(unittest.TestCase):
|
|
def test_four_bytes_and_side(self):
|
|
for front in [0,20]:
|
|
for rear in [0,30]:
|
|
for side in ['left','right']:
|
|
pos=[40]*4;i=0 if side=='left' else 1;pos[i]=front;pos[i+2]=rear
|
|
expected='both' if front==rear==0 else 'front' if front==0 else 'rear' if rear==0 else 'none'
|
|
self.assertEqual(select_active_door('can',{'positions':pos,'age_ms':10},side),(expected,True))
|
|
def test_invalid_never_becomes_clear(self):
|
|
for age in [-1,1001]:
|
|
active,valid=select_active_door('can',{'positions':[0]*4,'age_ms':age})
|
|
self.assertFalse(valid)
|
|
doors,risk=gate_risks({'regions':[]},[],active,valid)
|
|
self.assertEqual(risk['risk_level'],'unknown');self.assertIsNone(risk['risk_score'])
|
|
self.assertTrue(all(r['risk_level']=='unknown' for r in doors.values()))
|
|
def test_real_none_is_inactive(self):
|
|
active,valid=select_active_door('can',{'positions':[10]*4,'age_ms':0})
|
|
_,risk=gate_risks({'regions':[]},[],active,valid)
|
|
self.assertEqual(risk['risk_level'],'inactive')
|
|
|
|
class RiskTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.evaluator=DoorRiskEvaluator(DoorMaskSequence(constant_mask=ROOT/'annotations/constant_door_mask.json'))
|
|
def test_body_fallback_intersection_and_can_filter(self):
|
|
record={'boxes':[[0,0,1920,1536]],'track_ids':[42],'global_hands':[]}
|
|
raw,_=self.evaluator.evaluate(0,record,(1536,1920))
|
|
self.assertEqual(raw['risk_level'],'danger')
|
|
self.assertEqual(raw['regions'][0]['source'],'YOLO_BODY_BOX_FALLBACK')
|
|
assignments=[{'person_index':0,'track_id':42,'door_zone':'rear'}]
|
|
_,rear=gate_risks(raw,assignments,'rear',True)
|
|
_,front=gate_risks(raw,assignments,'front',True)
|
|
self.assertEqual(rear['risk_type'],'REAR_DANGER')
|
|
self.assertEqual(front['risk_type'],'FRONT_CLEAR')
|
|
def test_transition_keeps_unknown(self):
|
|
raw,_=self.evaluator.evaluate(0,{'boxes':[[0,0,1920,1536]],'track_ids':[42]},(1536,1920))
|
|
_,risk=gate_risks(raw,[{'person_index':0,'track_id':42,'door_zone':'transition'}],'front',True)
|
|
self.assertEqual(risk['risk_level'],'unknown');self.assertIsNone(risk['risk_score'])
|
|
def test_hand_overrides_whole_body_fallback(self):
|
|
hand={'person_id':1,'side':'left','keypoints':[[1,1],[50,1],[50,50],[1,50]]}
|
|
raw,_=self.evaluator.evaluate(0,{'boxes':[[0,0,1920,1536]],'track_ids':[42],'global_hands':[hand]},(1536,1920))
|
|
self.assertEqual(len(raw['regions']),1)
|
|
self.assertEqual(raw['regions'][0]['source'],'RTMW_HAND_KEYPOINTS')
|
|
def test_expired_tracker_state_pruned(self):
|
|
t=BoxTracker(max_age=30);t.update([[1,1,100,100]],0,(1536,1920));t.update([],31,(1536,1920))
|
|
self.assertEqual(t.tracks,{})
|
|
|
|
class OutputTests(unittest.TestCase):
|
|
def test_rotation_keeps_complete_utf8_records(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path=Path(tmp)/'risk.jsonl'
|
|
with JsonlWriter(path,19) as writer:
|
|
for i in range(6):writer.write('{"门":%d}\n'%i)
|
|
self.assertEqual(path.read_text(),'{"门":5}\n')
|
|
self.assertEqual(Path(str(path)+'.1').read_text(),'{"门":4}\n')
|
|
self.assertEqual(Path(str(path)+'.2').read_text(),'{"门":3}\n')
|
|
|
|
if __name__=='__main__':unittest.main()
|