348 lines
12 KiB
Python
348 lines
12 KiB
Python
"""Tests for JSON Schema validation."""
|
|
|
|
import jsonschema
|
|
import pytest
|
|
|
|
from pdf2imos.schema.validator import load_schema, validate_metadata
|
|
|
|
|
|
class TestSchemaLoading:
|
|
"""Tests for schema loading."""
|
|
|
|
def test_schema_loads_as_valid_json(self):
|
|
"""Test that the schema file is valid JSON."""
|
|
schema = load_schema()
|
|
assert isinstance(schema, dict)
|
|
assert "$schema" in schema
|
|
assert schema["$schema"] == "https://json-schema.org/draft/2020-12/schema"
|
|
|
|
def test_schema_has_required_properties(self):
|
|
"""Test that schema defines required properties."""
|
|
schema = load_schema()
|
|
assert "required" in schema
|
|
required = schema["required"]
|
|
assert "source_pdf" in required
|
|
assert "extraction_timestamp" in required
|
|
assert "part_name" in required
|
|
assert "overall_dimensions" in required
|
|
assert "parts" in required
|
|
assert "raw_annotations" in required
|
|
|
|
|
|
class TestValidMetadata:
|
|
"""Tests for valid metadata."""
|
|
|
|
@pytest.fixture
|
|
def valid_metadata(self):
|
|
"""Fixture for valid metadata."""
|
|
return {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [],
|
|
"raw_annotations": [],
|
|
}
|
|
|
|
def test_validate_valid_metadata(self, valid_metadata):
|
|
"""Test that valid metadata passes validation."""
|
|
# Should not raise
|
|
validate_metadata(valid_metadata)
|
|
|
|
def test_validate_metadata_with_parts(self):
|
|
"""Test validation with parts data."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "side_panel",
|
|
"dimensions": {
|
|
"width_mm": 18,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"material": {
|
|
"type": "plywood",
|
|
"thickness_mm": 18,
|
|
"finish": "veneer",
|
|
},
|
|
}
|
|
],
|
|
"raw_annotations": ["annotation1"],
|
|
}
|
|
# Should not raise
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_metadata_with_edgebanding(self):
|
|
"""Test validation with edgebanding data."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "shelf",
|
|
"dimensions": {
|
|
"width_mm": 550,
|
|
"height_mm": 20,
|
|
"depth_mm": 350,
|
|
},
|
|
"edgebanding": {
|
|
"top": {"material": "pvc", "thickness_mm": 2},
|
|
"bottom": None,
|
|
"left": {"material": "pvc", "thickness_mm": 2},
|
|
"right": {"material": "pvc", "thickness_mm": 2},
|
|
},
|
|
}
|
|
],
|
|
"raw_annotations": [],
|
|
}
|
|
# Should not raise
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_metadata_with_hardware(self):
|
|
"""Test validation with hardware data."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "door",
|
|
"dimensions": {
|
|
"width_mm": 300,
|
|
"height_mm": 700,
|
|
"depth_mm": 20,
|
|
},
|
|
"hardware": [
|
|
{
|
|
"type": "hinge",
|
|
"model": "BLUM-CLIP",
|
|
"position": "top_left",
|
|
},
|
|
{
|
|
"type": "hinge",
|
|
"model": "BLUM-CLIP",
|
|
"position": "bottom_left",
|
|
},
|
|
],
|
|
}
|
|
],
|
|
"raw_annotations": [],
|
|
}
|
|
# Should not raise
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_metadata_with_drilling(self):
|
|
"""Test validation with drilling data."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "panel",
|
|
"dimensions": {
|
|
"width_mm": 550,
|
|
"height_mm": 700,
|
|
"depth_mm": 18,
|
|
},
|
|
"drilling": [
|
|
{
|
|
"x_mm": 100,
|
|
"y_mm": 200,
|
|
"diameter_mm": 5,
|
|
"depth_mm": 10,
|
|
},
|
|
{
|
|
"x_mm": 200,
|
|
"y_mm": 300,
|
|
"diameter_mm": 8,
|
|
"depth_mm": 15,
|
|
},
|
|
],
|
|
}
|
|
],
|
|
"raw_annotations": [],
|
|
}
|
|
# Should not raise
|
|
validate_metadata(metadata)
|
|
|
|
|
|
class TestInvalidMetadata:
|
|
"""Tests for invalid metadata."""
|
|
|
|
def test_validate_empty_dict_raises(self):
|
|
"""Test that empty dict raises ValidationError."""
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata({})
|
|
|
|
def test_validate_missing_required_field_raises(self):
|
|
"""Test that missing required field raises ValidationError."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
# Missing "parts" and "raw_annotations"
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_negative_dimension_raises(self):
|
|
"""Test that negative dimension raises ValidationError."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": -1,
|
|
"height_mm": 100,
|
|
"depth_mm": 50,
|
|
},
|
|
"parts": [],
|
|
"raw_annotations": [],
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_zero_dimension_raises(self):
|
|
"""Test that zero dimension raises ValidationError (exclusiveMinimum)."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 0,
|
|
"height_mm": 100,
|
|
"depth_mm": 50,
|
|
},
|
|
"parts": [],
|
|
"raw_annotations": [],
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_wrong_type_raises(self):
|
|
"""Test that wrong type raises ValidationError."""
|
|
metadata = {
|
|
"source_pdf": 123, # Should be string
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [],
|
|
"raw_annotations": [],
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_additional_properties_raises(self):
|
|
"""Test that additional properties raise ValidationError."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [],
|
|
"raw_annotations": [],
|
|
"extra_field": "not allowed",
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_parts_missing_required_field_raises(self):
|
|
"""Test that parts missing required field raises ValidationError."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "panel",
|
|
# Missing "dimensions"
|
|
}
|
|
],
|
|
"raw_annotations": [],
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|
|
|
|
def test_validate_edgebanding_additional_properties_raises(self):
|
|
"""Test that edgebanding with additional properties raises ValidationError."""
|
|
metadata = {
|
|
"source_pdf": "test.pdf",
|
|
"extraction_timestamp": "2026-01-01T00:00:00Z",
|
|
"part_name": "cabinet",
|
|
"overall_dimensions": {
|
|
"width_mm": 600,
|
|
"height_mm": 720,
|
|
"depth_mm": 400,
|
|
},
|
|
"parts": [
|
|
{
|
|
"name": "shelf",
|
|
"dimensions": {
|
|
"width_mm": 550,
|
|
"height_mm": 20,
|
|
"depth_mm": 350,
|
|
},
|
|
"edgebanding": {
|
|
"top": {
|
|
"material": "pvc",
|
|
"thickness_mm": 2,
|
|
"extra_field": "not allowed",
|
|
},
|
|
"bottom": None,
|
|
"left": None,
|
|
"right": None,
|
|
},
|
|
}
|
|
],
|
|
"raw_annotations": [],
|
|
}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
validate_metadata(metadata)
|