Files
configforge/tests/unit/test_validators.py
7000pctAUTO 9d2494d1e4
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.8) (push) Has been cancelled
CI / test (3.9) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / build-package (push) Has been cancelled
Add test suite
2026-01-29 10:52:02 +00:00

130 lines
4.6 KiB
Python

"""Unit tests for validation logic."""
import json
import tempfile
import pytest
from click.testing import CliRunner
from jsonschema import ValidationError, validate
from configforge.commands.validate import validate as validate_cmd
def validate_against_schema(config: dict, schema: dict):
"""Validate configuration against a schema and return errors."""
errors = []
try:
validate(instance=config, schema=schema)
except ValidationError as e:
path = list(e.absolute_path) if e.absolute_path else []
errors.append({
"path": path,
"message": e.message,
"validator": e.validator,
"validator_value": e.validator_value,
})
return errors
def format_validation_error(error: ValidationError):
"""Format a jsonschema ValidationError."""
path = list(error.absolute_path) if error.absolute_path else []
return {
"path": path,
"message": error.message,
"validator": error.validator,
"validator_value": e.validator_value,
}
class TestValidateCommand:
"""Tests for the validate command."""
def test_validate_valid_config(self, temp_config_file, temp_schema_file):
"""Test validating a valid configuration."""
runner = CliRunner()
result = runner.invoke(validate_cmd, [temp_config_file, temp_schema_file])
assert result.exit_code == 0
def test_validate_invalid_config(self, sample_json_config, temp_schema_file):
"""Test validating an invalid configuration."""
invalid_config = sample_json_config.copy()
invalid_config["database"]["port"] = "invalid"
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(invalid_config, f)
filepath = f.name
try:
runner = CliRunner()
result = runner.invoke(validate_cmd, [filepath, temp_schema_file])
assert result.exit_code == 1
assert "error" in result.output.lower() or result.exit_code == 1
finally:
pass
def test_validate_dry_run(self, temp_config_file, temp_schema_file):
"""Test dry-run mode always exits with 0."""
runner = CliRunner()
result = runner.invoke(validate_cmd, [temp_config_file, temp_schema_file, "--dry-run"])
assert result.exit_code == 0
def test_validate_json_format(self, temp_config_file, temp_schema_file):
"""Test validation with JSON output format."""
runner = CliRunner()
result = runner.invoke(validate_cmd, [temp_config_file, temp_schema_file, "--format", "json"])
assert result.exit_code == 0
assert "valid" in result.output
def test_validate_table_format(self, temp_config_file, temp_schema_file):
"""Test validation with table output format."""
runner = CliRunner()
result = runner.invoke(validate_cmd, [temp_config_file, temp_schema_file, "--format", "table"])
assert result.exit_code == 0
class TestValidationLogic:
"""Tests for validation logic functions."""
def test_validate_against_schema_valid(self, sample_json_config, sample_json_schema):
"""Test validating valid config against schema."""
errors = validate_against_schema(sample_json_config, sample_json_schema)
assert len(errors) == 0
def test_validate_against_schema_invalid_type(self, sample_json_schema):
"""Test validation catches type errors."""
invalid_config = {
"database": {
"host": "localhost",
"port": "should_be_number",
"name": "test"
},
"server": {
"host": "0.0.0.0",
"port": 8080
}
}
errors = validate_against_schema(invalid_config, sample_json_schema)
assert len(errors) > 0
def test_validate_against_schema_missing_required(self, sample_json_schema):
"""Test validation catches missing required fields."""
invalid_config = {
"database": {
"host": "localhost"
}
}
errors = validate_against_schema(invalid_config, sample_json_schema)
assert len(errors) > 0
def test_format_validation_error(self):
"""Test formatting validation errors."""
schema = {"type": "string"}
try:
validate(instance=123, schema=schema)
except ValidationError as e:
formatted = format_validation_error(e)
assert "path" in formatted
assert "message" in formatted
assert "validator" in formatted