Test dataclass creation, immutability, equality, and hashability for ThermalState and ElectricalState. Also test PhysicsEngine stub methods.
215 lines
6.5 KiB
Python
215 lines
6.5 KiB
Python
"""Unit tests for physics state dataclasses and engine stub."""
|
|
|
|
import pytest
|
|
|
|
from py_dvt_ate.simulation.physics.engine import PhysicsEngine
|
|
from py_dvt_ate.simulation.physics.state import ElectricalState, ThermalState
|
|
|
|
|
|
class TestThermalState:
|
|
"""Tests for the ThermalState dataclass."""
|
|
|
|
def test_creation(self) -> None:
|
|
"""Test ThermalState can be created with valid values."""
|
|
state = ThermalState(
|
|
chamber_temperature=25.0,
|
|
case_temperature=30.0,
|
|
junction_temperature=35.0,
|
|
timestamp=0.0,
|
|
)
|
|
|
|
assert state.chamber_temperature == 25.0
|
|
assert state.case_temperature == 30.0
|
|
assert state.junction_temperature == 35.0
|
|
assert state.timestamp == 0.0
|
|
|
|
def test_immutability(self) -> None:
|
|
"""Test ThermalState is immutable (frozen dataclass)."""
|
|
state = ThermalState(
|
|
chamber_temperature=25.0,
|
|
case_temperature=30.0,
|
|
junction_temperature=35.0,
|
|
timestamp=0.0,
|
|
)
|
|
|
|
with pytest.raises(AttributeError):
|
|
state.chamber_temperature = 50.0 # type: ignore[misc]
|
|
|
|
def test_equality(self) -> None:
|
|
"""Test ThermalState equality comparison."""
|
|
state1 = ThermalState(
|
|
chamber_temperature=25.0,
|
|
case_temperature=30.0,
|
|
junction_temperature=35.0,
|
|
timestamp=0.0,
|
|
)
|
|
state2 = ThermalState(
|
|
chamber_temperature=25.0,
|
|
case_temperature=30.0,
|
|
junction_temperature=35.0,
|
|
timestamp=0.0,
|
|
)
|
|
|
|
assert state1 == state2
|
|
|
|
def test_hashable(self) -> None:
|
|
"""Test ThermalState is hashable (for use in sets/dicts)."""
|
|
state = ThermalState(
|
|
chamber_temperature=25.0,
|
|
case_temperature=30.0,
|
|
junction_temperature=35.0,
|
|
timestamp=0.0,
|
|
)
|
|
|
|
# Should not raise
|
|
hash(state)
|
|
{state} # Can be added to a set
|
|
|
|
|
|
class TestElectricalState:
|
|
"""Tests for the ElectricalState dataclass."""
|
|
|
|
def test_creation(self) -> None:
|
|
"""Test ElectricalState can be created with valid values."""
|
|
state = ElectricalState(
|
|
input_voltage=5.0,
|
|
output_voltage=3.3,
|
|
load_current=0.1,
|
|
quiescent_current=50e-6,
|
|
power_dissipation=0.17,
|
|
)
|
|
|
|
assert state.input_voltage == 5.0
|
|
assert state.output_voltage == 3.3
|
|
assert state.load_current == 0.1
|
|
assert state.quiescent_current == 50e-6
|
|
assert state.power_dissipation == 0.17
|
|
|
|
def test_immutability(self) -> None:
|
|
"""Test ElectricalState is immutable (frozen dataclass)."""
|
|
state = ElectricalState(
|
|
input_voltage=5.0,
|
|
output_voltage=3.3,
|
|
load_current=0.1,
|
|
quiescent_current=50e-6,
|
|
power_dissipation=0.17,
|
|
)
|
|
|
|
with pytest.raises(AttributeError):
|
|
state.output_voltage = 1.8 # type: ignore[misc]
|
|
|
|
def test_equality(self) -> None:
|
|
"""Test ElectricalState equality comparison."""
|
|
state1 = ElectricalState(
|
|
input_voltage=5.0,
|
|
output_voltage=3.3,
|
|
load_current=0.1,
|
|
quiescent_current=50e-6,
|
|
power_dissipation=0.17,
|
|
)
|
|
state2 = ElectricalState(
|
|
input_voltage=5.0,
|
|
output_voltage=3.3,
|
|
load_current=0.1,
|
|
quiescent_current=50e-6,
|
|
power_dissipation=0.17,
|
|
)
|
|
|
|
assert state1 == state2
|
|
|
|
|
|
class TestPhysicsEngineStub:
|
|
"""Tests for the PhysicsEngine stub."""
|
|
|
|
def test_creation_default(self) -> None:
|
|
"""Test PhysicsEngine can be created with defaults."""
|
|
engine = PhysicsEngine()
|
|
|
|
assert engine.dt == pytest.approx(0.01) # 100Hz -> 10ms
|
|
|
|
def test_creation_custom_rate(self) -> None:
|
|
"""Test PhysicsEngine with custom update rate."""
|
|
engine = PhysicsEngine(update_rate_hz=50.0)
|
|
|
|
assert engine.dt == pytest.approx(0.02) # 50Hz -> 20ms
|
|
|
|
def test_step_advances_time(self) -> None:
|
|
"""Test step() advances simulation time."""
|
|
engine = PhysicsEngine(update_rate_hz=100.0)
|
|
|
|
assert engine.simulation_time == pytest.approx(0.0)
|
|
engine.step()
|
|
assert engine.simulation_time == pytest.approx(0.01)
|
|
engine.step()
|
|
assert engine.simulation_time == pytest.approx(0.02)
|
|
|
|
def test_get_thermal_state(self) -> None:
|
|
"""Test get_thermal_state returns ThermalState."""
|
|
engine = PhysicsEngine()
|
|
|
|
state = engine.get_thermal_state()
|
|
|
|
assert isinstance(state, ThermalState)
|
|
assert state.chamber_temperature == 25.0 # Default
|
|
assert state.timestamp == 0.0
|
|
|
|
def test_get_electrical_state(self) -> None:
|
|
"""Test get_electrical_state returns ElectricalState."""
|
|
engine = PhysicsEngine()
|
|
|
|
state = engine.get_electrical_state()
|
|
|
|
assert isinstance(state, ElectricalState)
|
|
|
|
def test_set_chamber_setpoint(self) -> None:
|
|
"""Test set_chamber_setpoint updates setpoint."""
|
|
engine = PhysicsEngine()
|
|
|
|
engine.set_chamber_setpoint(85.0)
|
|
|
|
# Stub doesn't update chamber temp, just stores setpoint
|
|
state = engine.get_thermal_state()
|
|
assert state.chamber_temperature == 25.0 # Still at initial
|
|
|
|
def test_set_input_voltage(self) -> None:
|
|
"""Test set_input_voltage updates voltage."""
|
|
engine = PhysicsEngine()
|
|
|
|
engine.set_input_voltage(5.0)
|
|
|
|
state = engine.get_electrical_state()
|
|
assert state.input_voltage == 5.0
|
|
|
|
def test_set_load_current(self) -> None:
|
|
"""Test set_load_current updates current."""
|
|
engine = PhysicsEngine()
|
|
engine.set_output_enabled(True)
|
|
|
|
engine.set_load_current(0.1)
|
|
|
|
state = engine.get_electrical_state()
|
|
assert state.load_current == 0.1
|
|
|
|
def test_output_disabled_by_default(self) -> None:
|
|
"""Test output is disabled by default."""
|
|
engine = PhysicsEngine()
|
|
|
|
assert not engine.is_output_enabled
|
|
|
|
def test_enable_output(self) -> None:
|
|
"""Test set_output_enabled enables output."""
|
|
engine = PhysicsEngine()
|
|
|
|
engine.set_output_enabled(True)
|
|
|
|
assert engine.is_output_enabled
|
|
|
|
def test_load_current_zero_when_disabled(self) -> None:
|
|
"""Test load current is zero when output disabled."""
|
|
engine = PhysicsEngine()
|
|
engine.set_load_current(0.1)
|
|
|
|
state = engine.get_electrical_state()
|
|
|
|
assert state.load_current == 0.0 # Disabled, so zero
|