""" Tests for parameter validation module. Testing validation of all input parameters with boundary conditions, invalid types, and edge cases. """ import pytest import math from laser_control.validators import ParameterValidator from laser_control.exceptions import ( ValidationError, TemperatureOutOfRangeError, CurrentOutOfRangeError, InvalidParameterError ) from laser_control.models import VariationType class TestTemperatureValidation: """Test temperature parameter validation.""" def test_valid_temperature_range(self): """Test temperatures within valid range.""" # Valid temperatures should pass assert ParameterValidator.validate_temperature(15.0, "temp1") == 15.0 assert ParameterValidator.validate_temperature(25.5, "temp2") == 25.5 assert ParameterValidator.validate_temperature(40.0, "temp1") == 40.0 def test_temperature_below_minimum(self): """Test temperature below minimum threshold.""" with pytest.raises(TemperatureOutOfRangeError) as exc_info: ParameterValidator.validate_temperature(10.0, "temp1") assert "temp1" in str(exc_info.value) assert "15.0" in str(exc_info.value) # min value def test_temperature_above_maximum(self): """Test temperature above maximum threshold.""" with pytest.raises(TemperatureOutOfRangeError) as exc_info: ParameterValidator.validate_temperature(45.0, "temp2") assert "temp2" in str(exc_info.value) assert "40.0" in str(exc_info.value) # max value def test_temperature_invalid_type(self): """Test invalid temperature type.""" with pytest.raises(InvalidParameterError) as exc_info: ParameterValidator.validate_temperature("invalid", "temp1") assert "temp1" in str(exc_info.value) assert "number" in str(exc_info.value).lower() def test_temperature_nan_value(self): """Test NaN temperature value.""" with pytest.raises(InvalidParameterError) as exc_info: ParameterValidator.validate_temperature(float('nan'), "temp1") assert "NaN" in str(exc_info.value) def test_temperature_inf_value(self): """Test infinite temperature value.""" with pytest.raises(InvalidParameterError) as exc_info: ParameterValidator.validate_temperature(float('inf'), "temp2") assert "infinite" in str(exc_info.value).lower() def test_temperature_none_value(self): """Test None temperature value.""" with pytest.raises(InvalidParameterError) as exc_info: ParameterValidator.validate_temperature(None, "temp1") assert "temp1" in str(exc_info.value) class TestCurrentValidation: """Test current parameter validation.""" def test_valid_current_range(self): """Test currents within valid range.""" assert ParameterValidator.validate_current(15.0, "current1") == 15.0 assert ParameterValidator.validate_current(37.5, "current2") == 37.5 assert ParameterValidator.validate_current(60.0, "current1") == 60.0 def test_current_below_minimum(self): """Test current below minimum threshold.""" with pytest.raises(CurrentOutOfRangeError) as exc_info: ParameterValidator.validate_current(10.0, "current1") assert "current1" in str(exc_info.value) assert "15.0" in str(exc_info.value) # min value def test_current_above_maximum(self): """Test current above maximum threshold.""" with pytest.raises(CurrentOutOfRangeError) as exc_info: ParameterValidator.validate_current(65.0, "current2") assert "current2" in str(exc_info.value) assert "60.0" in str(exc_info.value) # max value def test_current_invalid_type(self): """Test invalid current type.""" with pytest.raises(InvalidParameterError) as exc_info: ParameterValidator.validate_current([15, 20], "current1") assert "current1" in str(exc_info.value) def test_current_negative_value(self): """Test negative current value.""" with pytest.raises(CurrentOutOfRangeError) as exc_info: ParameterValidator.validate_current(-5.0, "current1") assert "current1" in str(exc_info.value) class TestVariationParameterValidation: """Test variation mode parameter validation.""" def test_valid_current_variation_params(self): """Test valid parameters for current variation.""" params = { 'min_value': 20.0, 'max_value': 50.0, 'step': 0.5, 'time_step': 50, # microseconds 'delay_time': 5 # milliseconds } validated = ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert validated['min_value'] == 20.0 assert validated['max_value'] == 50.0 assert validated['step'] == 0.5 def test_variation_min_greater_than_max(self): """Test min value greater than max value.""" params = { 'min_value': 50.0, 'max_value': 20.0, 'step': 0.5, 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert "min" in str(exc_info.value).lower() assert "max" in str(exc_info.value).lower() def test_variation_invalid_step(self): """Test invalid step values.""" # Zero step params = { 'min_value': 20.0, 'max_value': 50.0, 'step': 0, 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert "step" in str(exc_info.value).lower() # Negative step params['step'] = -0.5 with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert "step" in str(exc_info.value).lower() def test_variation_step_too_small(self): """Test step value too small for current.""" params = { 'min_value': 20.0, 'max_value': 50.0, 'step': 0.001, # Too small for current (min 0.002) 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD2 ) assert "step" in str(exc_info.value).lower() assert "0.002" in str(exc_info.value) def test_variation_step_too_large(self): """Test step value too large.""" params = { 'min_value': 20.0, 'max_value': 50.0, 'step': 10.0, # Too large for current (max 0.5) 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert "step" in str(exc_info.value).lower() assert "0.5" in str(exc_info.value) def test_valid_temperature_variation_params(self): """Test valid parameters for temperature variation.""" params = { 'min_value': 20.0, 'max_value': 35.0, 'step': 0.1, 'time_step': 50, 'delay_time': 5 } validated = ParameterValidator.validate_variation_params( params, VariationType.CHANGE_TEMPERATURE_LD1 ) assert validated['min_value'] == 20.0 assert validated['max_value'] == 35.0 assert validated['step'] == 0.1 def test_temperature_variation_step_bounds(self): """Test temperature variation step boundaries.""" params = { 'min_value': 20.0, 'max_value': 35.0, 'step': 0.02, # Too small (min 0.05) 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_TEMPERATURE_LD2 ) assert "0.05" in str(exc_info.value) params['step'] = 2.0 # Too large (max 1.0) with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_TEMPERATURE_LD1 ) assert "1.0" in str(exc_info.value) def test_missing_required_params(self): """Test missing required parameters.""" params = { 'min_value': 20.0, 'max_value': 50.0 # Missing step, time_step, delay_time } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, VariationType.CHANGE_CURRENT_LD1 ) assert "required" in str(exc_info.value).lower() def test_invalid_variation_type(self): """Test invalid variation type.""" params = { 'min_value': 20.0, 'max_value': 50.0, 'step': 0.5, 'time_step': 50, 'delay_time': 5 } with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_variation_params( params, "INVALID_TYPE" ) assert "variation type" in str(exc_info.value).lower() class TestTimeParameterValidation: """Test time parameter validation.""" def test_valid_time_params(self): """Test valid time parameters.""" step_time, delay_time = ParameterValidator.validate_time_params(50, 5) assert step_time == 50 assert delay_time == 5 step_time, delay_time = ParameterValidator.validate_time_params(20, 3) assert step_time == 20 assert delay_time == 3 step_time, delay_time = ParameterValidator.validate_time_params(100, 10) assert step_time == 100 assert delay_time == 10 def test_time_step_below_minimum(self): """Test time step below minimum.""" with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_time_params(10, 5) # Min is 20 assert "time step" in str(exc_info.value).lower() assert "20" in str(exc_info.value) def test_time_step_above_maximum(self): """Test time step above maximum.""" with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_time_params(150, 5) # Max is 100 assert "time step" in str(exc_info.value).lower() assert "100" in str(exc_info.value) def test_delay_time_below_minimum(self): """Test delay time below minimum.""" with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_time_params(50, 1) # Min is 3 assert "delay" in str(exc_info.value).lower() assert "3" in str(exc_info.value) def test_delay_time_above_maximum(self): """Test delay time above maximum.""" with pytest.raises(ValidationError) as exc_info: ParameterValidator.validate_time_params(50, 15) # Max is 10 assert "delay" in str(exc_info.value).lower() assert "10" in str(exc_info.value) def test_time_params_invalid_type(self): """Test invalid type for time parameters.""" with pytest.raises(InvalidParameterError): ParameterValidator.validate_time_params("50", 5) with pytest.raises(InvalidParameterError): ParameterValidator.validate_time_params(50, [5]) def test_time_params_float_conversion(self): """Test float to int conversion for time parameters.""" step_time, delay_time = ParameterValidator.validate_time_params(50.7, 5.2) assert step_time == 50 # Should be truncated to int assert delay_time == 5 class TestManualModeValidation: """Test manual mode parameter validation.""" def test_validate_all_manual_params(self): """Test validation of all manual mode parameters at once.""" result = ParameterValidator.validate_manual_mode_params( temp1=25.0, temp2=30.0, current1=40.0, current2=35.0 ) assert result['temp1'] == 25.0 assert result['temp2'] == 30.0 assert result['current1'] == 40.0 assert result['current2'] == 35.0 def test_manual_mode_invalid_combination(self): """Test invalid parameter combinations in manual mode.""" # One invalid parameter should fail all validation with pytest.raises(ValidationError): ParameterValidator.validate_manual_mode_params( temp1=25.0, temp2=30.0, current1=70.0, # Too high current2=35.0 ) def test_manual_mode_boundary_values(self): """Test boundary values for manual mode.""" # All minimum values result = ParameterValidator.validate_manual_mode_params( temp1=15.0, temp2=15.0, current1=15.0, current2=15.0 ) assert all(v in [15.0] for v in result.values()) # All maximum values result = ParameterValidator.validate_manual_mode_params( temp1=40.0, temp2=40.0, current1=60.0, current2=60.0 ) assert result['temp1'] == 40.0 assert result['temp2'] == 40.0 assert result['current1'] == 60.0 assert result['current2'] == 60.0