import pytest from datetime import datetime, timedelta from src.models.cell import Cell, CellLimits, MeasureValues @pytest.fixture def cell_limits(): return CellLimits(min_volt=3000, max_volt=4200, max_curr=1000) @pytest.fixture def test_cell(cell_limits): return Cell(id=1, cell_limits=cell_limits, nom_capacity=2000.0) # 2000mAh capacity def generate_measurement_sequence(current_pattern: list[int], interval_seconds: float = 1.0, voltage: int = 3700, temperature: int = 25): """Helper to generate a sequence of measurements with specified timing""" measurements = [] start_time = datetime.now() last_time = start_time for current in current_pattern: measurement = MeasureValues(voltage=voltage, current=current, temperature=temperature) # Set up timing for this measurement current_time = last_time + timedelta(seconds=interval_seconds) duration = (current_time - last_time).total_seconds() measurements.append((measurement, duration)) last_time = current_time return measurements def test_normal_cycles(test_cell:Cell): """Test capacity estimation with normal charge/discharge cycles""" # Create pattern for 2 complete cycles at 0.25C (500mA) # Each charge should take ~4 hours = 14400 seconds current_pattern = ( [500] * 14400 + # 4h charge at 0.25C [-500] * 14400 + # 4h discharge [500] * 14400 + # 4h charge [-500] * 14400 # 4h discharge ) # Add measurements for measurement, duration in generate_measurement_sequence(current_pattern): test_cell.measurements_duration.append(duration) test_cell.measurements.append(measurement) capacity = test_cell.estimate_capacity() assert 95.0 <= capacity <= 100.0, "Expected near 100% capacity for normal cycles" def test_degraded_capacity(test_cell:Cell): """Test capacity estimation with shorter charging cycles (degraded cell)""" # Create pattern for 2 cycles at 0.25C but with shorter duration (~75% capacity) current_pattern = ( [500] * 10800 + # 3h charge at 0.25C [-500] * 10800 + # 3h discharge [500] * 10800 + # 3h charge [-500] * 10800 # 3h discharge ) for measurement, duration in generate_measurement_sequence(current_pattern): test_cell.measurements_duration.append(duration) test_cell.measurements.append(measurement) capacity = test_cell.estimate_capacity() assert 70.0 <= capacity <= 80.0, "Expected ~75% capacity for degraded cell" def test_empty_measurements(test_cell:Cell): """Test capacity estimation with no measurements""" capacity = test_cell.estimate_capacity() assert capacity == -1.0, "Expected -1.0 for no measurements" def test_no_charge_cycles(test_cell:Cell): """Test capacity estimation with no charging cycles""" # Only discharge cycles current_pattern = [-500] * 1000 for measurement, duration in generate_measurement_sequence(current_pattern): test_cell.measurements_duration.append(duration) test_cell.measurements.append(measurement) capacity = test_cell.estimate_capacity() assert capacity == -1.0, "Expected -1.0 for no charge cycles" def test_incomplete_cycle(test_cell:Cell): """Test capacity estimation with incomplete cycle""" # One complete cycle and one incomplete current_pattern = ( [500] * 14400 + # 4h charge [-500] * 14400 + # 4h discharge [500] * 7200 # 2h partial charge ) for measurement, duration in generate_measurement_sequence(current_pattern): test_cell.measurements_duration.append(duration) test_cell.measurements.append(measurement) capacity = test_cell.estimate_capacity() assert 70.0 <= capacity <= 80.0, "Expected capacity calculation from incomplete cycle"