"""Tests for schema validation.""" import json import tempfile from pathlib import Path from src.confgen.validator import SchemaValidator class TestSchemaValidator: """Tests for SchemaValidator.""" def setup_method(self): """Set up test fixtures.""" self.schema_data = { "type": "object", "properties": { "name": {"type": "string"}, "port": {"type": "integer", "minimum": 1, "maximum": 65535}, "enabled": {"type": "boolean"}, "timeout": {"type": "number", "minimum": 0}, }, "required": ["name", "port"], } with tempfile.NamedTemporaryFile( mode="w", suffix=".json", delete=False ) as f: json.dump(self.schema_data, f) self.schema_path = f.name self.validator = SchemaValidator(self.schema_path) def teardown_method(self): """Clean up test fixtures.""" Path(self.schema_path).unlink() def test_validate_valid_config(self): """Test validating a valid configuration.""" config = {"name": "myapp", "port": 8080, "enabled": True, "timeout": 30} is_valid, errors = self.validator.validate(config) assert is_valid is True assert len(errors) == 0 def test_validate_missing_required_field(self): """Test that missing required field fails validation.""" config = {"name": "myapp"} is_valid, errors = self.validator.validate(config) assert is_valid is False assert len(errors) > 0 assert any("port" in error for error in errors) def test_validate_invalid_type(self): """Test that invalid type fails validation.""" config = {"name": "myapp", "port": "not_a_number"} is_valid, errors = self.validator.validate(config) assert is_valid is False assert len(errors) > 0 def test_validate_integer_out_of_range(self): """Test that integer out of range fails validation.""" config = {"name": "myapp", "port": 70000} is_valid, errors = self.validator.validate(config) assert is_valid is False assert any("minimum" in error or "maximum" in error for error in errors) def test_validate_boolean_type(self): """Test validating boolean fields.""" config = {"name": "myapp", "port": 8080, "enabled": "not_boolean"} is_valid, errors = self.validator.validate(config) assert is_valid is False def test_format_error_with_path(self): """Test error formatting includes the path.""" schema_with_nested = { "type": "object", "properties": { "database": { "type": "object", "properties": { "host": {"type": "string"}, "port": {"type": "integer"}, }, "required": ["host"], }, }, } with tempfile.NamedTemporaryFile( mode="w", suffix=".json", delete=False ) as f: json.dump(schema_with_nested, f) nested_schema_path = f.name validator = SchemaValidator(nested_schema_path) config = {"database": {"port": "invalid"}} is_valid, errors = validator.validate(config) assert is_valid is False Path(nested_schema_path).unlink() def test_get_schema_summary(self): """Test getting a summary of the schema.""" summary = self.validator.get_schema_summary() assert summary["type"] == "object" assert "name" in summary["required"] assert "port" in summary["properties"] assert "type" in summary["properties"]["name"] def test_check_property_exists(self): """Test checking if property exists in data.""" config = {"database": {"host": "localhost"}} assert self.validator.check_property_exists(config, "database.host") is True assert self.validator.check_property_exists(config, "database.port") is False assert self.validator.check_property_exists(config, "nonexistent") is False def test_validate_nested_object(self): """Test validating nested objects.""" schema = { "type": "object", "properties": { "database": { "type": "object", "properties": { "host": {"type": "string"}, "port": {"type": "integer"}, }, "required": ["host", "port"], }, }, "required": ["database"], } with tempfile.NamedTemporaryFile( mode="w", suffix=".json", delete=False ) as f: json.dump(schema, f) nested_schema_path = f.name validator = SchemaValidator(nested_schema_path) config = {"database": {"host": "localhost", "port": 5432}} is_valid, errors = validator.validate(config) assert is_valid is True Path(nested_schema_path).unlink() def test_validate_with_default_values(self): """Test that validation ignores missing optional fields.""" config = {"name": "myapp", "port": 8080} is_valid, errors = self.validator.validate(config) assert is_valid is True