"""Tests for shared error taxonomy and helpers.""" import pytest from transcription.errors import AppError from transcription.errors import ErrorCategory from transcription.errors import build_error_envelope from transcription.errors import canonical_error_category from transcription.errors import classify_unexpected_error from transcription.errors import new_error_id @pytest.mark.unit class TestErrorCategoryContract: """Verify stable category identifiers.""" def test_category_values_match_policy_contract(self): """Error category values match docs/error_handling.md identifiers.""" assert ErrorCategory.VALIDATION.value == "validation_error" assert ErrorCategory.USER_INPUT.value == "user_input_error" assert ErrorCategory.NOT_FOUND.value == "not_found_error" assert ErrorCategory.CONFLICT.value == "conflict_error" assert ErrorCategory.EXTERNAL_PROVIDER.value == "external_provider_error" assert ErrorCategory.EXTERNAL_TIMEOUT.value == "external_timeout_error" assert ErrorCategory.PROCESSING.value == "processing_error" assert ErrorCategory.INFRA_TRANSIENT.value == "infrastructure_transient_error" assert ErrorCategory.INFRA_PERSISTENT.value == "infrastructure_persistent_error" assert ErrorCategory.INTERNAL_UNEXPECTED.value == "internal_unexpected_error" @pytest.mark.unit class TestAppErrorHelpers: """Verify helper behavior for IDs and normalization.""" def test_new_error_id_returns_short_identifier(self): """new_error_id returns a short non-empty identifier.""" value = new_error_id() assert isinstance(value, str) assert len(value) == 8 def test_classify_unexpected_error_returns_internal_unexpected(self): """Unexpected exceptions are normalized to internal_unexpected_error.""" err = classify_unexpected_error(RuntimeError("boom"), operation="unit.test") assert isinstance(err, AppError) assert err.category == ErrorCategory.INTERNAL_UNEXPECTED assert "unit.test" in err.message assert "boom" in err.message assert err.suggestion assert err.error_id def test_envelope_categories_use_canonical_contract_values(self): """API/UI envelope categories are normalized to canonical short identifiers.""" expected_mapping = { ErrorCategory.VALIDATION: "validation", ErrorCategory.USER_INPUT: "validation", ErrorCategory.NOT_FOUND: "not_found", ErrorCategory.CONFLICT: "conflict", ErrorCategory.EXTERNAL_PROVIDER: "external", ErrorCategory.EXTERNAL_TIMEOUT: "timeout", ErrorCategory.INFRA_TRANSIENT: "timeout", ErrorCategory.PROCESSING: "internal", ErrorCategory.INFRA_PERSISTENT: "internal", ErrorCategory.INTERNAL_UNEXPECTED: "internal", } for category, expected in expected_mapping.items(): err = AppError("x", category=category) assert canonical_error_category(err) == expected assert build_error_envelope(err).category == expected