"""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)