"""Testing file 'cli/db/cell_spec.py'."""
import sys
import unittest
from dataclasses import FrozenInstanceError
from pathlib import Path
try:
from cli.db.cell_spec import CellSpec
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).parents[3]))
from cli.db.cell_spec import CellSpec
def make_valid_kwargs():
"""Return a base set of valid kwargs for CellSpec."""
return {
"name": "X100",
"manufacturer": "Acme",
"shape": "prismatic",
"chemistry": "NMC",
"height": 0.120,
"length": 0.250,
"width": 0.070,
"weight": 0.750,
"temperature_max": 60.0,
"temperature_min": -20.0,
"voltage_min": 2.5,
"voltage_max": 4.2,
"voltage_nom": 3.7,
}
class TestCellSpecPostInit(unittest.TestCase):
"""Tests for CellSpec.__post_init__ validation."""
def test_valid_instance(self) -> None:
"""Should construct without errors for valid input."""
kwargs = make_valid_kwargs()
spec = CellSpec(**kwargs)
self.assertEqual(spec.name, "X100")
self.assertEqual(spec.manufacturer, "Acme")
self.assertEqual(spec.shape, "prismatic")
self.assertEqual(spec.voltage_nom, 3.7)
def test_string_type_validation(self) -> None:
"""Should raise TypeError if any string field is not a str."""
kwargs = make_valid_kwargs()
kwargs["manufacturer"] = 123
with self.assertRaises(TypeError) as ctx:
CellSpec(**kwargs)
self.assertIn("not a str", str(ctx.exception))
def test_float_type_validation(self) -> None:
"""Should raise TypeError if any numeric field is not a float."""
kwargs = make_valid_kwargs()
kwargs["height"] = 1
with self.assertRaises(TypeError) as ctx:
CellSpec(**kwargs)
self.assertIn("not a float", str(ctx.exception))
def test_cylindrical_width_length_mismatch(self) -> None:
"""Should raise ValueError if shape is cylindrical and width != length."""
kwargs = make_valid_kwargs()
kwargs["shape"] = "cylindrical"
kwargs["length"] = 0.018
kwargs["width"] = 0.017
with self.assertRaises(ValueError) as ctx:
CellSpec(**kwargs)
self.assertIn("cylindrical", str(ctx.exception))
def test_cylindrical_width_length_match(self) -> None:
"""Should raise ValueError if shape is cylindrical and width != length."""
kwargs = make_valid_kwargs()
kwargs["shape"] = "cylindrical"
kwargs["length"] = 0.018
kwargs["width"] = 0.018
CellSpec(**kwargs)
def test_temperature_range_invalid(self) -> None:
"""Should raise ValueError if temperature_max < temperature_min."""
kwargs = make_valid_kwargs()
kwargs["temperature_max"] = -10.0
kwargs["temperature_min"] = 0.0
with self.assertRaises(ValueError) as ctx:
CellSpec(**kwargs)
self.assertIn("temperature", str(ctx.exception).lower())
def test_voltage_range_invalid(self) -> None:
"""Should raise ValueError if voltage_max < voltage_min."""
kwargs = make_valid_kwargs()
kwargs["voltage_min"] = 3.0
kwargs["voltage_max"] = 2.9
with self.assertRaises(ValueError) as ctx:
CellSpec(**kwargs)
self.assertIn("voltage", str(ctx.exception).lower())
def test_nominal_voltage_out_of_range_high(self) -> None:
"""Should raise ValueError if voltage_nom > voltage_max."""
kwargs = make_valid_kwargs()
kwargs["voltage_nom"] = 4.3
with self.assertRaises(ValueError) as ctx:
CellSpec(**kwargs)
self.assertIn("Nom. cell voltage", str(ctx.exception))
def test_nominal_voltage_out_of_range_low(self) -> None:
"""Should raise ValueError if voltage_nom < voltage_min."""
kwargs = make_valid_kwargs()
kwargs["voltage_nom"] = 2.4
with self.assertRaises(ValueError) as ctx:
CellSpec(**kwargs)
self.assertIn("Nom. cell voltage", str(ctx.exception))
def test_frozen_dataclass_immutability(self) -> None:
"""Should be immutable: assigning any attribute raises FrozenInstanceError."""
spec = CellSpec(**make_valid_kwargs())
with self.assertRaises(FrozenInstanceError):
spec.name = "NewName"
if __name__ == "__main__":
unittest.main()