import tempfile import unittest from pathlib import Path from servos import ControleServos from braco import Braco class HW: def __init__(self): self.calls=[] def pulse(self,ch,us): self.calls.append((ch,us)) def off(self,ch): self.calls.append((ch,None)) class Tests(unittest.TestCase): def setUp(self): self.tmp=tempfile.TemporaryDirectory(); self.hw=HW() self.servos=ControleServos(Path(self.tmp.name)/'servos.json',self.hw) self.arm=Braco(Path(self.tmp.name)/'braco.json',self.servos) def tearDown(self): self.servos.close(); self.tmp.cleanup() def test_no_startup_movement(self): self.assertEqual(self.hw.calls,[]) self.assertEqual(len(self.arm.status()['articulacoes']),7) def test_calibration_single_and_pair(self): self.arm.calibrate(1,1700) self.assertEqual(self.hw.calls,[(1,1700)]) self.hw.calls.clear();self.arm.calibrate(5,1800) self.assertEqual(self.hw.calls,[(5,1800),(6,1200)]) with self.assertRaises(ValueError):self.arm.calibrate(1,2600) def test_pair_mirrors_and_all_channels_expire(self): self.arm.move([90,90,90,90,90,95,90]) self.assertIn((5,1556),self.hw.calls); self.assertIn((6,1444),self.hw.calls) self.assertEqual(set(self.servos.active),set(range(8))) self.servos.expire(float('inf')); self.assertEqual(len(self.servos.active),0) def test_full_validation_before_any_write(self): for pose in [[0]*7,[90]*6,[90]*6+[True]]: with self.assertRaises(ValueError): self.arm.move(pose) self.assertEqual(self.hw.calls,[]) def test_save_and_import_invalid_poses_are_atomic(self): data=self.arm.status(); data['posturas']=[dict(nome='Centro',angulos=[90]*7)] self.arm.save(data) other=Braco(self.arm.path,self.servos) self.assertEqual(other.status()['posturas'],data['posturas']) data['posturas'].append(dict(nome='Inválida',angulos=[180]*7)) with self.assertRaises(ValueError): self.arm.save(data) self.assertEqual(len(self.arm.status()['posturas']),1) if __name__=='__main__': unittest.main()