Spaces:
Running on Zero
Running on Zero
| """Tests for response enhancer module.""" | |
| import re | |
| from unittest.mock import patch | |
| import pytest | |
| from src.response_enhancer import ResponseEnhancer, get_response_enhancer | |
| def enhancer(): | |
| """Create a ResponseEnhancer instance for testing.""" | |
| with patch("src.response_enhancer.get_config") as mock_config: | |
| mock_config.return_value.get.return_value = "Tin Hoang" | |
| return ResponseEnhancer() | |
| # --- ResponseEnhancer Tests --- | |
| def test_enhancer_init(enhancer): | |
| """Test ResponseEnhancer initialization.""" | |
| assert enhancer is not None | |
| assert enhancer.name == "Tin Hoang" | |
| assert len(enhancer.negative_patterns) > 0 | |
| assert len(enhancer.positive_closings) > 0 | |
| def test_enhance_empty_response(enhancer): | |
| """Test enhance handles empty response.""" | |
| result = enhancer.enhance("") | |
| assert result == "" | |
| # Whitespace-only gets stripped and returns empty | |
| result = enhancer.enhance(" ") | |
| assert result.strip() == "" | |
| def test_enhance_none_response(enhancer): | |
| """Test enhance handles None response.""" | |
| result = enhancer.enhance(None) | |
| assert result is None | |
| def test_enhance_simple_response(enhancer): | |
| """Test enhance keeps simple responses unchanged.""" | |
| response = "Tin is an AI Engineer with expertise in machine learning." | |
| result = enhancer.enhance(response) | |
| assert "Tin" in result or "AI Engineer" in result | |
| def test_rewrite_no_info_pattern(enhancer): | |
| """Test rewriting 'don't have information' pattern.""" | |
| response = "However, I don't have any specific information about that topic." | |
| result = enhancer.enhance(response) | |
| # Should not contain the negative phrase | |
| assert "don't have" not in result.lower() | |
| assert "however" not in result.lower() or "directly" in result.lower() | |
| def test_rewrite_uncertain_pattern(enhancer): | |
| """Test rewriting uncertain statements.""" | |
| response = "I'm not sure about the specific salary expectations." | |
| result = enhancer.enhance(response) | |
| # Should not contain the uncertain phrase | |
| assert "not sure" not in result.lower() | |
| def test_rewrite_cannot_provide_pattern(enhancer): | |
| """Test rewriting 'cannot provide' statements.""" | |
| response = "I cannot provide more information about his personal life." | |
| result = enhancer.enhance(response) | |
| # Should not contain the negative phrase | |
| assert "cannot provide" not in result.lower() | |
| def test_rewrite_do_not_have_pattern(enhancer): | |
| """Test rewriting 'do not have' statements.""" | |
| response = "I do not have any details about that project." | |
| result = enhancer.enhance(response) | |
| # Should not contain the negative phrase | |
| assert "do not have" not in result.lower() | |
| def test_add_positive_closing_negative_ending(enhancer): | |
| """Test adding positive closing for negative endings.""" | |
| response = "The profile covers relevant experience. However, there's no information available." | |
| result = enhancer.enhance(response) | |
| # Should have some form of positive closing | |
| assert len(result) >= len(response) | |
| def test_no_double_closing(enhancer): | |
| """Test no double closing when already has contact suggestion.""" | |
| response = "For more details, feel free to connect directly with me." | |
| result = enhancer.enhance(response) | |
| # Should not add another closing | |
| assert result.count("directly") <= 2 | |
| def test_fix_markdown_inline_numbered_list(enhancer): | |
| """Test fixing inline numbered lists.""" | |
| response = "Key skills: 1. Python 2. Machine Learning 3. Deep Learning" | |
| result = enhancer.enhance(response) | |
| # Should format the list properly | |
| assert result is not None | |
| def test_fix_markdown_already_formatted_list(enhancer): | |
| """Test preserving already formatted lists.""" | |
| response = """Key skills: | |
| 1. Python | |
| 2. Machine Learning | |
| 3. Deep Learning""" | |
| result = enhancer.enhance(response) | |
| # Should preserve the formatting | |
| assert "1." in result | |
| assert "2." in result | |
| assert "3." in result | |
| def test_cleanup_double_spaces(enhancer): | |
| """Test cleanup of double spaces.""" | |
| response = "This has multiple spaces." | |
| result = enhancer.enhance(response) | |
| assert " " not in result | |
| def test_cleanup_punctuation(enhancer): | |
| """Test cleanup of awkward punctuation.""" | |
| response = "This has extra spaces before punctuation ." | |
| result = enhancer.enhance(response) | |
| assert " ." not in result | |
| def test_cleanup_double_punctuation(enhancer): | |
| """Test cleanup of double punctuation.""" | |
| response = "This has double punctuation.." | |
| result = enhancer.enhance(response) | |
| # Should have single punctuation | |
| assert ".." not in result | |
| def test_enhance_with_context_job_search(enhancer): | |
| """Test enhance_with_context adds job-related closing.""" | |
| question = "What job roles are you looking for?" | |
| response = "The candidate has experience in AI and ML engineering." | |
| result = enhancer.enhance_with_context(response, question) | |
| # Should add contact suggestion for job-related questions | |
| assert "direct" in result.lower() or "contact" in result.lower() | |
| def test_enhance_with_context_already_has_contact(enhancer): | |
| """Test enhance_with_context doesn't add duplicate contact suggestion.""" | |
| question = "What position are you seeking?" | |
| response = "Looking for ML roles. Feel free to reach out to discuss opportunities." | |
| result = enhancer.enhance_with_context(response, question) | |
| # Should not add another contact suggestion | |
| assert result.count("reach out") <= 1 | |
| def test_enhance_with_context_non_job_question(enhancer): | |
| """Test enhance_with_context for non-job questions.""" | |
| question = "What are your technical skills?" | |
| response = "Strong background in Python, TensorFlow, and PyTorch." | |
| result = enhancer.enhance_with_context(response, question) | |
| # Should be similar to original (no job-specific closing added) | |
| assert "Python" in result | |
| # --- Rewrite Function Tests --- | |
| def test_rewrite_no_info_consistent(enhancer): | |
| """Test _rewrite_no_info produces consistent output for same topic.""" | |
| pattern = r"(?:I\s+)?(?:don'?t|do\s+not)\s+have\s+(?:any\s+)?(?:more\s+)?(?:information|details|data)\s+(?:about|on|regarding)\s+([^.!?]+)" | |
| text = "I don't have any information about salary expectations." | |
| match = re.search(pattern, text, re.IGNORECASE) | |
| if match: | |
| result1 = enhancer._rewrite_no_info(match) | |
| result2 = enhancer._rewrite_no_info(match) | |
| # Same topic should produce same rewrite | |
| assert result1 == result2 | |
| def test_rewrite_uncertain_consistent(enhancer): | |
| """Test _rewrite_uncertain produces consistent output for same topic.""" | |
| pattern = r"(?:I'm|I am)\s+(?:not\s+)?(?:un)?(?:sure|certain|aware)\s+(?:about|of)\s+([^.!?]+)" | |
| text = "I'm not sure about the project timeline." | |
| match = re.search(pattern, text, re.IGNORECASE) | |
| if match: | |
| result1 = enhancer._rewrite_uncertain(match) | |
| result2 = enhancer._rewrite_uncertain(match) | |
| # Same topic should produce same rewrite | |
| assert result1 == result2 | |
| def test_rewrite_cannot_provide_consistent(enhancer): | |
| """Test _rewrite_cannot_provide produces consistent output for same topic.""" | |
| pattern = r"(?:I\s+)?(?:cannot|can'?t|unable to)\s+(?:provide|share|give)\s+(?:more\s+)?(?:information|details)\s+(?:about|on)\s+([^.!?]+)" | |
| text = "I cannot provide more details about that." | |
| match = re.search(pattern, text, re.IGNORECASE) | |
| if match: | |
| result1 = enhancer._rewrite_cannot_provide(match) | |
| result2 = enhancer._rewrite_cannot_provide(match) | |
| # Same topic should produce same rewrite | |
| assert result1 == result2 | |
| # --- Markdown Formatting Tests --- | |
| def test_fix_markdown_bullet_list(enhancer): | |
| """Test handling bullet lists.""" | |
| response = """Skills include: | |
| - Python | |
| - Machine Learning | |
| - Deep Learning""" | |
| result = enhancer._fix_markdown_formatting(response) | |
| assert "-" in result | |
| assert "Python" in result | |
| def test_fix_markdown_mixed_content(enhancer): | |
| """Test handling mixed content.""" | |
| response = """Overview paragraph. | |
| 1. First item | |
| 2. Second item | |
| Another paragraph.""" | |
| result = enhancer._fix_markdown_formatting(response) | |
| assert "1." in result | |
| assert "2." in result | |
| def test_fix_markdown_no_multiple_blank_lines(enhancer): | |
| """Test no multiple blank lines.""" | |
| response = """First paragraph. | |
| Second paragraph.""" | |
| result = enhancer._fix_markdown_formatting(response) | |
| # Should not have multiple consecutive blank lines | |
| assert "\n\n\n" not in result | |
| # --- Factory Function Tests --- | |
| def test_get_response_enhancer(): | |
| """Test get_response_enhancer returns instance.""" | |
| with patch("src.response_enhancer.get_config") as mock_config: | |
| mock_config.return_value.get.return_value = "Test Name" | |
| result = get_response_enhancer() | |
| assert isinstance(result, ResponseEnhancer) | |