""" Unit tests for settings validation in SettingsManager. Tests the _validate_setting_value method to ensure proper input validation for all configurable settings that could cause crashes or accessibility issues. """ import pytest import sys from pathlib import Path # Import the settings manager from fenrirscreenreader.core.settingsManager import SettingsManager @pytest.mark.unit @pytest.mark.settings class TestSpeechSettingsValidation: """Test validation of speech-related settings.""" def setup_method(self): """Create a SettingsManager instance for each test.""" self.manager = SettingsManager() def test_speech_rate_valid_range(self): """Speech rate should accept values between 0.0 and 3.0.""" # Valid boundary values self.manager._validate_setting_value("speech", "rate", 0.0) self.manager._validate_setting_value("speech", "rate", 1.5) self.manager._validate_setting_value("speech", "rate", 3.0) def test_speech_rate_rejects_negative(self): """Speech rate should reject negative values.""" with pytest.raises(ValueError, match="must be between 0.0 and 3.0"): self.manager._validate_setting_value("speech", "rate", -0.1) def test_speech_rate_rejects_too_high(self): """Speech rate should reject values above 3.0.""" with pytest.raises(ValueError, match="must be between 0.0 and 3.0"): self.manager._validate_setting_value("speech", "rate", 10.0) def test_speech_pitch_valid_range(self): """Speech pitch should accept values between 0.0 and 2.0.""" self.manager._validate_setting_value("speech", "pitch", 0.0) self.manager._validate_setting_value("speech", "pitch", 1.0) self.manager._validate_setting_value("speech", "pitch", 2.0) def test_speech_pitch_rejects_invalid(self): """Speech pitch should reject out-of-range values.""" with pytest.raises(ValueError, match="must be between 0.0 and 2.0"): self.manager._validate_setting_value("speech", "pitch", -1.0) with pytest.raises(ValueError, match="must be between 0.0 and 2.0"): self.manager._validate_setting_value("speech", "pitch", 5.0) def test_speech_volume_valid_range(self): """Speech volume should accept values between 0.0 and 1.5.""" self.manager._validate_setting_value("speech", "volume", 0.0) self.manager._validate_setting_value("speech", "volume", 1.0) self.manager._validate_setting_value("speech", "volume", 1.5) def test_speech_volume_rejects_negative(self): """Speech volume should reject negative values.""" with pytest.raises(ValueError, match="must be between 0.0 and 1.5"): self.manager._validate_setting_value("speech", "volume", -0.5) def test_speech_driver_whitelisted(self): """Speech driver should only accept whitelisted values.""" # Valid drivers self.manager._validate_setting_value("speech", "driver", "speechdDriver") self.manager._validate_setting_value("speech", "driver", "genericDriver") self.manager._validate_setting_value("speech", "driver", "dummyDriver") # Invalid driver with pytest.raises(ValueError, match="Invalid speech driver"): self.manager._validate_setting_value( "speech", "driver", "nonexistentDriver" ) @pytest.mark.unit @pytest.mark.settings class TestSoundSettingsValidation: """Test validation of sound-related settings.""" def setup_method(self): """Create a SettingsManager instance for each test.""" self.manager = SettingsManager() def test_sound_volume_valid_range(self): """Sound volume should accept values between 0.0 and 1.5.""" self.manager._validate_setting_value("sound", "volume", 0.0) self.manager._validate_setting_value("sound", "volume", 0.7) self.manager._validate_setting_value("sound", "volume", 1.5) def test_sound_volume_rejects_invalid(self): """Sound volume should reject out-of-range values.""" with pytest.raises(ValueError, match="must be between 0.0 and 1.5"): self.manager._validate_setting_value("sound", "volume", -0.1) with pytest.raises(ValueError, match="must be between 0.0 and 1.5"): self.manager._validate_setting_value("sound", "volume", 2.0) def test_sound_driver_whitelisted(self): """Sound driver should only accept whitelisted values.""" # Valid drivers self.manager._validate_setting_value("sound", "driver", "genericDriver") self.manager._validate_setting_value("sound", "driver", "gstreamerDriver") self.manager._validate_setting_value("sound", "driver", "dummyDriver") # Invalid driver with pytest.raises(ValueError, match="Invalid sound driver"): self.manager._validate_setting_value("sound", "driver", "invalidDriver") @pytest.mark.unit @pytest.mark.settings class TestDriverValidation: """Test validation of driver selection settings.""" def setup_method(self): """Create a SettingsManager instance for each test.""" self.manager = SettingsManager() def test_screen_driver_whitelisted(self): """Screen driver should only accept whitelisted values.""" # Valid drivers self.manager._validate_setting_value("screen", "driver", "vcsaDriver") self.manager._validate_setting_value("screen", "driver", "ptyDriver") self.manager._validate_setting_value("screen", "driver", "dummyDriver") # Invalid driver with pytest.raises(ValueError, match="Invalid screen driver"): self.manager._validate_setting_value("screen", "driver", "unknownDriver") def test_keyboard_driver_whitelisted(self): """Keyboard driver should only accept whitelisted values.""" # Valid drivers self.manager._validate_setting_value("keyboard", "driver", "evdevDriver") self.manager._validate_setting_value("keyboard", "driver", "ptyDriver") self.manager._validate_setting_value("keyboard", "driver", "atspiDriver") self.manager._validate_setting_value("keyboard", "driver", "dummyDriver") # Invalid driver with pytest.raises(ValueError, match="Invalid input driver"): self.manager._validate_setting_value("keyboard", "driver", "badDriver") @pytest.mark.unit @pytest.mark.settings class TestGeneralSettingsValidation: """Test validation of general settings.""" def setup_method(self): """Create a SettingsManager instance for each test.""" self.manager = SettingsManager() def test_debug_level_valid_range(self): """Debug level should accept values 0-3.""" self.manager._validate_setting_value("general", "debug_level", 0) self.manager._validate_setting_value("general", "debug_level", 1) self.manager._validate_setting_value("general", "debug_level", 2) self.manager._validate_setting_value("general", "debug_level", 3) def test_debug_level_rejects_invalid(self): """Debug level should reject values outside 0-3.""" with pytest.raises(ValueError, match="must be between 0 and 3"): self.manager._validate_setting_value("general", "debug_level", -1) with pytest.raises(ValueError, match="must be between 0 and 3"): self.manager._validate_setting_value("general", "debug_level", 10) @pytest.mark.unit @pytest.mark.settings class TestValidationSkipsUnknownSettings: """Test that validation doesn't error on unknown settings.""" def setup_method(self): """Create a SettingsManager instance for each test.""" self.manager = SettingsManager() def test_unknown_section_no_error(self): """Unknown sections should not raise errors during validation.""" # Should not raise - validation only applies to known critical settings self.manager._validate_setting_value("unknown_section", "setting", "value") def test_unknown_setting_no_error(self): """Unknown settings in known sections should not raise errors.""" # Should not raise - only specific critical settings are validated self.manager._validate_setting_value("speech", "unknown_setting", "value")