"""Standalone generator configuration and independent resource cleanup.""" from dataclasses import replace import unittest from unittest import mock from python_app.generator_sweep.config import GeneratorSweepConfig, resolve_generator_sweep_config from python_app.generator_sweep.runner import GeneratorSweepRunner class GeneratorSweepTest(unittest.TestCase): def test_frequency_grid_includes_stop_with_and_without_an_exact_step(self) -> None: for step, expected in ((2, (10, 12, 14, 15)), (5, (10, 15))): config = GeneratorSweepConfig(start_hz=10, stop_hz=15, step_hz=step) self.assertEqual(resolve_generator_sweep_config(config).frequencies_hz, expected) config = GeneratorSweepConfig(start_hz=10, stop_hz=15, points=3) self.assertEqual(resolve_generator_sweep_config(config).frequencies_hz, (10, 12, 15)) def test_malformed_types_nonfinite_values_and_excessive_grids_fail_before_open(self) -> None: valid = GeneratorSweepConfig(points=3) for changes in ({'points': 3.5}, {'port': True}, {'sweep_start_pin': 5.5}, {'power_dbm': float('inf')}, {'hold_time_ms': float('nan')}, {'points': 1_000_001}, {'points': 0, 'step_hz': 1, 'stop_hz': 10 ** 10}): with self.subTest(changes=changes), self.assertRaises(ValueError): resolve_generator_sweep_config(replace(valid, **changes)) def test_each_cleanup_failure_still_releases_the_other_resources(self) -> None: for failure in ('pwm_stop', 'device_idle', 'device_close', 'marker_reset', 'marker_close'): with self.subTest(failure=failure): runner = GeneratorSweepRunner(GeneratorSweepConfig(points=3)) runner._pwm = mock.Mock() runner._markers = mock.Mock() device = runner._device = mock.Mock(is_connected=True) actions = { 'pwm_stop': runner._pwm.disable, 'device_idle': device.generator.set_idle, 'device_close': device.disconnect, 'marker_reset': runner._markers.reset_to_idle, 'marker_close': runner._markers.close, } actions[failure].side_effect = OSError('cleanup failure') with self.assertLogs('python_app.generator_sweep.runner', level='WARNING'): runner._close() for action in actions.values(): action.assert_called_once() runner._pwm.close.assert_called_once() self.assertIsNone(runner._device)