DocUA's picture
Add property-based tests for verification mode functionality
a3934b1
# test_error_handling.py
"""
Unit tests for error handling and validation in verification mode.
Tests error message display, validation, and user-friendly error handling.
Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
"""
import pytest
from src.core.verification_error_handler import (
VerificationErrorHandler,
VerificationError,
ErrorType,
)
class TestErrorMessageDisplay:
"""Tests for error message display (Subtask 9.1)."""
def test_error_message_for_missing_feedback(self):
"""Test error message for missing feedback."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_FEEDBACK
)
assert "Feedback Required" in error_msg
assert "select if this message was correct or incorrect" in error_msg
assert "✓ Correct" in error_msg or "Correct" in error_msg
assert "✗ Incorrect" in error_msg or "Incorrect" in error_msg
def test_error_message_for_missing_correction(self):
"""Test error message for missing correction."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_CORRECTION
)
assert "Correction Required" in error_msg
assert "didn't select" in error_msg or "select" in error_msg
assert "GREEN" in error_msg
assert "YELLOW" in error_msg
assert "RED" in error_msg
def test_error_message_for_csv_export_failure(self):
"""Test error message for CSV export failure."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.CSV_EXPORT_FAILURE
)
assert "Download Failed" in error_msg
assert "couldn't download" in error_msg or "couldn't" in error_msg
assert "try again" in error_msg.lower()
def test_error_message_for_no_verified_messages(self):
"""Test error message for no verified messages."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.NO_VERIFIED_MESSAGES
)
assert "No Results to Export" in error_msg
assert "haven't verified" in error_msg or "verified" in error_msg
assert "at least one" in error_msg
def test_error_message_for_invalid_notes(self):
"""Test error message for invalid notes."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.INVALID_NOTES
)
assert "Notes Too Long" in error_msg
assert "500 characters" in error_msg
def test_error_message_for_session_load_failure(self):
"""Test error message for session load failure."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.SESSION_LOAD_FAILURE
)
assert "Session Load Failed" in error_msg
assert "couldn't load" in error_msg or "load" in error_msg
def test_error_message_for_dataset_load_failure(self):
"""Test error message for dataset load failure."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.DATASET_LOAD_FAILURE
)
assert "Dataset Load Failed" in error_msg
assert "couldn't load" in error_msg or "load" in error_msg
def test_error_message_for_storage_failure(self):
"""Test error message for storage failure."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.STORAGE_FAILURE
)
assert "Save Failed" in error_msg
assert "couldn't save" in error_msg or "save" in error_msg
def test_error_messages_are_user_friendly(self):
"""Test that all error messages are user-friendly (non-technical)."""
for error_type in ErrorType:
error_msg = VerificationErrorHandler.get_user_friendly_message(error_type)
# Should not contain technical jargon
assert "exception" not in error_msg.lower()
assert "traceback" not in error_msg.lower()
assert "stacktrace" not in error_msg.lower()
# Should contain helpful suggestion
assert "💡" in error_msg or "try" in error_msg.lower() or "select" in error_msg.lower()
def test_error_message_format_includes_title(self):
"""Test that error messages include a title."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_CORRECTION
)
# Should have markdown bold title
assert "**" in error_msg
def test_error_message_format_includes_suggestion(self):
"""Test that error messages include a suggestion."""
error_msg = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_FEEDBACK
)
# Should have suggestion with 💡 emoji
assert "💡" in error_msg
class TestFeedbackValidation:
"""Tests for feedback validation."""
def test_validate_feedback_correct_is_valid(self):
"""Test that correct feedback is valid."""
is_valid, error_msg = VerificationErrorHandler.validate_feedback_selection(
is_correct=True
)
assert is_valid is True
assert error_msg is None
def test_validate_feedback_incorrect_without_correction_is_invalid(self):
"""Test that incorrect feedback without correction is invalid."""
is_valid, error_msg = VerificationErrorHandler.validate_feedback_selection(
is_correct=False,
ground_truth_label=""
)
assert is_valid is False
assert error_msg is not None
assert "Correction Required" in error_msg
def test_validate_feedback_incorrect_with_valid_correction_is_valid(self):
"""Test that incorrect feedback with valid correction is valid."""
for correction in ["green", "yellow", "red"]:
is_valid, error_msg = VerificationErrorHandler.validate_feedback_selection(
is_correct=False,
ground_truth_label=correction
)
assert is_valid is True
assert error_msg is None
def test_validate_feedback_incorrect_with_invalid_correction_is_invalid(self):
"""Test that incorrect feedback with invalid correction is invalid."""
is_valid, error_msg = VerificationErrorHandler.validate_feedback_selection(
is_correct=False,
ground_truth_label="invalid"
)
assert is_valid is False
assert error_msg is not None
assert "Invalid Selection" in error_msg or "invalid" in error_msg.lower()
def test_validate_feedback_correction_case_insensitive(self):
"""Test that correction validation is case-insensitive."""
for correction in ["GREEN", "Yellow", "RED"]:
is_valid, error_msg = VerificationErrorHandler.validate_feedback_selection(
is_correct=False,
ground_truth_label=correction
)
assert is_valid is True
assert error_msg is None
class TestNotesValidation:
"""Tests for notes field validation."""
def test_validate_notes_empty_is_valid(self):
"""Test that empty notes are valid."""
is_valid, error_msg = VerificationErrorHandler.validate_notes_field("")
assert is_valid is True
assert error_msg is None
def test_validate_notes_valid_text_is_valid(self):
"""Test that valid notes text is valid."""
notes = "This is a valid note explaining the correction"
is_valid, error_msg = VerificationErrorHandler.validate_notes_field(notes)
assert is_valid is True
assert error_msg is None
def test_validate_notes_at_limit_is_valid(self):
"""Test that notes at 500 character limit are valid."""
notes = "x" * 500
is_valid, error_msg = VerificationErrorHandler.validate_notes_field(notes)
assert is_valid is True
assert error_msg is None
def test_validate_notes_exceeding_limit_is_invalid(self):
"""Test that notes exceeding 500 characters are invalid."""
notes = "x" * 501
is_valid, error_msg = VerificationErrorHandler.validate_notes_field(notes)
assert is_valid is False
assert error_msg is not None
assert "500 characters" in error_msg
def test_validate_notes_significantly_exceeding_limit_is_invalid(self):
"""Test that notes significantly exceeding limit are invalid."""
notes = "x" * 1000
is_valid, error_msg = VerificationErrorHandler.validate_notes_field(notes)
assert is_valid is False
assert error_msg is not None
class TestCSVExportValidation:
"""Tests for CSV export validation."""
def test_validate_csv_export_with_no_messages_is_invalid(self):
"""Test that CSV export with no verified messages is invalid."""
is_valid, error_msg = VerificationErrorHandler.validate_csv_export_preconditions(
verified_count=0
)
assert is_valid is False
assert error_msg is not None
assert "No Results to Export" in error_msg
def test_validate_csv_export_with_one_message_is_valid(self):
"""Test that CSV export with one verified message is valid."""
is_valid, error_msg = VerificationErrorHandler.validate_csv_export_preconditions(
verified_count=1
)
assert is_valid is True
assert error_msg is None
def test_validate_csv_export_with_multiple_messages_is_valid(self):
"""Test that CSV export with multiple verified messages is valid."""
is_valid, error_msg = VerificationErrorHandler.validate_csv_export_preconditions(
verified_count=10
)
assert is_valid is True
assert error_msg is None
class TestErrorCreation:
"""Tests for error creation and formatting."""
def test_create_error_includes_user_message(self):
"""Test that created error includes user-friendly message."""
error = VerificationErrorHandler.create_error(
ErrorType.MISSING_CORRECTION,
"Technical error details"
)
assert isinstance(error, VerificationError)
assert error.error_type == ErrorType.MISSING_CORRECTION
assert error.message == "Technical error details"
assert "Correction Required" in error.user_message
def test_format_error_for_display(self):
"""Test that error is formatted correctly for display."""
error = VerificationErrorHandler.create_error(
ErrorType.CSV_EXPORT_FAILURE,
"CSV generation failed"
)
formatted = VerificationErrorHandler.format_error_for_display(error)
assert "Download Failed" in formatted
assert "try again" in formatted.lower()
def test_get_retry_suggestion(self):
"""Test that retry suggestion is provided."""
suggestion = VerificationErrorHandler.get_retry_suggestion(
ErrorType.CSV_EXPORT_FAILURE
)
assert suggestion is not None
assert len(suggestion) > 0
assert "try" in suggestion.lower() or "again" in suggestion.lower()
class TestErrorHandlerIntegration:
"""Integration tests for error handler."""
def test_error_handler_provides_consistent_messages(self):
"""Test that error handler provides consistent messages."""
msg1 = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_CORRECTION
)
msg2 = VerificationErrorHandler.get_user_friendly_message(
ErrorType.MISSING_CORRECTION
)
assert msg1 == msg2
def test_all_error_types_have_messages(self):
"""Test that all error types have user-friendly messages."""
for error_type in ErrorType:
msg = VerificationErrorHandler.get_user_friendly_message(error_type)
assert msg is not None
assert len(msg) > 0
assert "**" in msg # Should have title
assert "💡" in msg # Should have suggestion
def test_validation_functions_return_consistent_format(self):
"""Test that validation functions return consistent format."""
# All validation functions should return (bool, Optional[str])
result1 = VerificationErrorHandler.validate_feedback_selection(True)
result2 = VerificationErrorHandler.validate_notes_field("")
result3 = VerificationErrorHandler.validate_csv_export_preconditions(1)
assert isinstance(result1, tuple) and len(result1) == 2
assert isinstance(result2, tuple) and len(result2) == 2
assert isinstance(result3, tuple) and len(result3) == 2
assert isinstance(result1[0], bool)
assert isinstance(result2[0], bool)
assert isinstance(result3[0], bool)