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