Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/validate-schemas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@ on:
jobs:
validate-schemas:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "latest"

- name: Install dependencies
run: |
uv sync --extra dev

- name: Validate JSON schema files with pytest
run: |
uv run pytest -v

- name: Check for JSON syntax in all JSON files
run: |
echo "🔍 Double-checking JSON syntax with jq..."
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ coverage.xml
.hypothesis/
.pytest_cache/

# Direnv files (https://direnv.net/)
.direnv/
.envrc

# Environments
.env
.venv
Expand Down
111 changes: 40 additions & 71 deletions tests/test_schema_validation.py
Original file line number Diff line number Diff line change
@@ -1,88 +1,57 @@
#!/usr/bin/env python3
"""
Pytest-based validation tests for JSON schema files.
This test suite validates that all .json files are valid JSON and valid JSON schemas.
"""

import json
import glob
import os
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Tuple

import pytest
import jsonschema
import pytest
from jsonschema import Draft7Validator, Draft202012Validator

REPO_ROOT = Path(__file__).parent.parent
ALL_JSON_FILES = sorted(glob.glob(str(REPO_ROOT / "**" / "*.json"), recursive=True))


@dataclass
class JsonTestCase:
name: str
file_path: Path


ALL_JSON_TEST_CASES = [
JsonTestCase(name=json_file, file_path=Path(json_file))
for json_file in ALL_JSON_FILES
]


class TestSchemaValidation:
"""Test class for validating JSON schemas."""
@pytest.mark.parametrize(
"test_case",
[pytest.param(tc, id=tc.name) for tc in ALL_JSON_TEST_CASES],
)
def test_collect_and_validate_all_json_files(test_case: JsonTestCase) -> None:
"""Collect and validate all JSON files at once for better reporting."""

@pytest.fixture(scope="class")
def repo_root(self):
"""Get the repository root directory."""
return Path(__file__).parent.parent
with open(test_case.file_path, "r", encoding="utf-8") as f:
json.load(f)

@pytest.fixture(scope="class")
def json_files(self, repo_root):
"""Get all JSON files in the repository."""
os.chdir(repo_root)
return sorted(glob.glob("**/*.json", recursive=True))

def validate_json_file(self, file_path: str) -> Tuple[bool, str]:
"""Validate that a file contains valid JSON."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
json.load(f)
return True, ""
except json.JSONDecodeError as e:
return False, f"Invalid JSON: {e}"
except Exception as e:
return False, f"Error reading file: {e}"
@pytest.mark.parametrize(
"test_case",
[pytest.param(tc, id=tc.name) for tc in ALL_JSON_TEST_CASES],
)
def test_collect_and_validate_all_json_schema_files(test_case: JsonTestCase) -> None:
"""Collect and validate all JSON files at once for better reporting."""

def validate_json_schema(self, file_path: str) -> Tuple[bool, str]:
"""Validate that a JSON file is a valid JSON schema."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
schema = json.load(f)

# Try to create a validator - this will fail if it's not a valid schema
# First try Draft 2020-12, then fall back to Draft 7
try:
Draft202012Validator.check_schema(schema)
except jsonschema.SchemaError:
try:
Draft7Validator.check_schema(schema)
except jsonschema.SchemaError as e:
return False, f"Invalid JSON schema: {e}"

return True, ""
except json.JSONDecodeError as e:
return False, f"Invalid JSON: {e}"
except Exception as e:
return False, f"Error validating schema: {e}"
with open(test_case.file_path, "r", encoding="utf-8") as f:
schema = json.load(f)

def test_collect_and_validate_all_json_files(self, json_files):
"""Collect and validate all JSON files at once for better reporting."""
if not json_files:
pytest.skip("No JSON files found to validate")

errors = []

for json_file in json_files:
# Test JSON syntax
is_valid_json, json_error = self.validate_json_file(json_file)
if not is_valid_json:
errors.append(f"❌ {json_file}: {json_error}")
continue

# Test JSON schema validity
is_valid_schema, schema_error = self.validate_json_schema(json_file)
if not is_valid_schema:
errors.append(f"❌ {json_file}: {schema_error}")

if errors:
error_msg = f"Found {len(errors)} JSON validation errors:\n" + "\n".join(errors)
pytest.fail(error_msg)

print(f"✅ All {len(json_files)} JSON files passed validation!")
# Try to create a validator - this will fail if it's not a valid schema
# First try Draft 2020-12, then fall back to Draft 7
try:
Draft202012Validator.check_schema(schema)
except jsonschema.SchemaError:
Draft7Validator.check_schema(schema)