Add test suite for confgen
This commit is contained in:
167
app/tests/test_validator.py
Normal file
167
app/tests/test_validator.py
Normal file
@@ -0,0 +1,167 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user