resumate / tests /test_gradio.py
gperdrizet's picture
Updated tests of get_processed_data() function
3ec2cfd
raw
history blame
16.5 kB
"""
Unit tests for the gradio module.
"""
import unittest
from unittest.mock import patch, MagicMock, mock_open
import tempfile
import os
from functions import gradio
class TestProcessInputs(unittest.TestCase):
"""Test cases for the process_inputs function."""
def test_no_inputs_provided(self):
"""Test when no inputs are provided."""
result = gradio.process_inputs(None, "", "", "")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("❌ No GitHub profile URL provided", result)
self.assertIn("❌ Job post not provided", result)
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
def test_all_inputs_provided_success(self):
"""Test when all inputs are provided and successful."""
# Mock LinkedIn PDF file
mock_pdf = MagicMock()
mock_pdf.name = "test_resume.pdf"
# Mock successful extraction results
mock_linkedin_result = {
"status": "success",
"structured_text": {"sections": {}, "llm_formatted": "test content"},
"metadata": {"filename": "test_resume.pdf"}
}
mock_github_result = {
"status": "success",
"repositories": [{"name": "test-repo"}],
"metadata": {"username": "testuser"}
}
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
patch('functions.gradio.get_github_repositories') as mock_github, \
patch('functions.gradio.write_resume') as mock_write_resume:
mock_linkedin.return_value = mock_linkedin_result
mock_github.return_value = mock_github_result
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(
mock_pdf,
"https://github.com/testuser",
"Job posting text here",
"Please emphasize technical skills"
)
self.assertIn("βœ… LinkedIn Resume PDF uploaded", result)
self.assertIn("βœ… Text extraction successful", result)
self.assertIn("βœ… GitHub Profile URL provided", result)
self.assertIn("βœ… GitHub list download successful", result)
self.assertIn("βœ… Job post text provided", result)
self.assertIn("βœ… Additional instructions provided", result)
self.assertIn("βœ… Resume generated successfully", result)
# Verify write_resume was called with user instructions
mock_write_resume.assert_called_with(mock_linkedin_result, "Please emphasize technical skills")
@patch('functions.gradio.extract_text_from_linkedin_pdf')
@patch('functions.gradio.write_resume')
def test_linkedin_extraction_failure(self, mock_write_resume, mock_extract):
"""Test LinkedIn PDF extraction failure."""
mock_pdf = MagicMock()
mock_pdf.name = "test_resume.pdf"
mock_extract.return_value = {
"status": "error",
"message": "Failed to read PDF"
}
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(mock_pdf, "", "", "")
self.assertIn("βœ… LinkedIn Resume PDF uploaded", result)
self.assertIn("❌ Text extraction failed: Failed to read PDF", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since extraction failed
mock_write_resume.assert_not_called()
@patch('functions.gradio.extract_text_from_linkedin_pdf')
@patch('functions.gradio.write_resume')
def test_linkedin_extraction_warning(self, mock_write_resume, mock_extract):
"""Test LinkedIn PDF extraction warning."""
mock_pdf = MagicMock()
mock_pdf.name = "test_resume.pdf"
mock_extract.return_value = {
"status": "warning",
"message": "No text found in PDF"
}
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(mock_pdf, "", "", "")
self.assertIn("βœ… LinkedIn Resume PDF uploaded", result)
self.assertIn("⚠️ Text extraction: No text found in PDF", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since extraction had warning status
mock_write_resume.assert_not_called()
@patch('functions.gradio.get_github_repositories')
@patch('functions.gradio.write_resume')
def test_github_retrieval_failure(self, mock_write_resume, mock_github):
"""Test GitHub repository retrieval failure."""
mock_github.return_value = {
"status": "error",
"message": "User not found"
}
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(None, "https://github.com/nonexistent", "", "")
self.assertIn("βœ… GitHub Profile URL provided", result)
self.assertIn("❌ GitHub extraction failed: User not found", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since no LinkedIn data
mock_write_resume.assert_not_called()
def test_whitespace_only_inputs(self):
"""Test inputs with only whitespace."""
result = gradio.process_inputs(None, " ", " ", " ")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("❌ No GitHub profile URL provided", result)
self.assertIn("❌ Job post not provided", result)
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
@patch('functions.gradio.write_resume')
def test_job_post_with_content(self, mock_write_resume):
"""Test job post with actual content."""
job_text = "Software Engineer position at Tech Company"
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(None, "", job_text, "")
self.assertIn("βœ… Job post text provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since no LinkedIn data
mock_write_resume.assert_not_called()
@patch('functions.gradio.logger')
@patch('functions.gradio.write_resume')
def test_logging_calls(self, mock_write_resume, mock_logger):
"""Test that appropriate logging calls are made."""
mock_pdf = MagicMock()
mock_pdf.name = "test.pdf"
mock_write_resume.return_value = "Generated resume content"
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract, \
patch('functions.gradio.get_github_repositories') as mock_github:
mock_extract.return_value = {"status": "success"}
mock_github.return_value = {"status": "success", "metadata": {"username": "test"}}
gradio.process_inputs(mock_pdf, "https://github.com/test", "job text", "custom instructions")
# Verify logging calls were made
mock_logger.info.assert_called()
@patch('functions.gradio.write_resume')
def test_user_instructions_with_content(self, mock_write_resume):
"""Test user instructions with actual content."""
instructions = "Please emphasize leadership skills and highlight remote work experience"
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(None, "", "", instructions)
self.assertIn("βœ… Additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since no valid extraction result
mock_write_resume.assert_not_called()
@patch('functions.gradio.write_resume')
def test_user_instructions_empty(self, mock_write_resume):
"""Test user instructions when empty."""
mock_write_resume.return_value = "Generated resume content"
result = gradio.process_inputs(None, "", "", "")
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
# Verify write_resume was NOT called since no valid extraction result
mock_write_resume.assert_not_called()
class TestGetProcessedData(unittest.TestCase):
"""Test cases for the get_processed_data function."""
def test_no_inputs(self):
"""Test with no inputs provided."""
result = gradio.get_processed_data(None, "", "", "")
self.assertIsNone(result["linkedin"])
self.assertIsNone(result["github"])
self.assertIsNone(result["job_post"])
self.assertIsNone(result["user_instructions"])
self.assertEqual(len(result["errors"]), 0)
def test_all_successful_inputs(self):
"""Test with all successful inputs."""
mock_pdf = MagicMock()
mock_pdf.name = "test.pdf"
mock_linkedin_result = {
"status": "success",
"structured_text": {"sections": {}, "llm_formatted": "content"}
}
mock_github_result = {
"status": "success",
"repositories": [{"name": "repo"}],
"metadata": {"username": "user"}
}
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
patch('functions.gradio.get_github_repositories') as mock_github:
mock_linkedin.return_value = mock_linkedin_result
mock_github.return_value = mock_github_result
result = gradio.get_processed_data(
mock_pdf,
"https://github.com/user",
"Job posting content",
"Custom instructions"
)
self.assertEqual(result["linkedin"], mock_linkedin_result)
self.assertEqual(result["github"], mock_github_result)
self.assertEqual(result["job_post"], "Job posting content")
self.assertEqual(result["user_instructions"], "Custom instructions")
self.assertEqual(len(result["errors"]), 0)
def test_linkedin_error(self):
"""Test with LinkedIn processing error."""
mock_pdf = MagicMock()
mock_pdf.name = "test.pdf"
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract:
mock_extract.return_value = {
"status": "error",
"message": "PDF read failed"
}
result = gradio.get_processed_data(mock_pdf, "", "", "")
self.assertIsNone(result["linkedin"])
self.assertEqual(len(result["errors"]), 1)
self.assertIn("LinkedIn: PDF read failed", result["errors"])
def test_github_error(self):
"""Test with GitHub processing error."""
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {
"status": "error",
"message": "User not found"
}
result = gradio.get_processed_data(None, "https://github.com/invalid", "", "")
self.assertIsNone(result["github"])
self.assertEqual(len(result["errors"]), 1)
self.assertIn("GitHub: User not found", result["errors"])
def test_multiple_errors(self):
"""Test with multiple processing errors."""
mock_pdf = MagicMock()
mock_pdf.name = "test.pdf"
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
patch('functions.gradio.get_github_repositories') as mock_github:
mock_linkedin.return_value = {
"status": "error",
"message": "LinkedIn error"
}
mock_github.return_value = {
"status": "error",
"message": "GitHub error"
}
result = gradio.get_processed_data(
mock_pdf,
"https://github.com/user",
"",
""
)
self.assertIsNone(result["linkedin"])
self.assertIsNone(result["github"])
self.assertEqual(len(result["errors"]), 2)
self.assertIn("LinkedIn: LinkedIn error", result["errors"])
self.assertIn("GitHub: GitHub error", result["errors"])
def test_job_post_whitespace_handling(self):
"""Test job post whitespace handling."""
# Test with leading/trailing whitespace
result = gradio.get_processed_data(None, "", " Job content ", "")
self.assertEqual(result["job_post"], "Job content")
# Test with only whitespace
result = gradio.get_processed_data(None, "", " ", "")
self.assertIsNone(result["job_post"])
# Test with empty string
result = gradio.get_processed_data(None, "", "", "")
self.assertIsNone(result["job_post"])
def test_github_url_whitespace_handling(self):
"""Test GitHub URL whitespace handling."""
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "repositories": []}
# Test with leading/trailing whitespace
result = gradio.get_processed_data(None, " https://github.com/user ", "", "")
mock_github.assert_called_with(" https://github.com/user ")
# Test with only whitespace - should not call function
mock_github.reset_mock()
result = gradio.get_processed_data(None, " ", "", "")
mock_github.assert_not_called()
def test_data_structure_consistency(self):
"""Test that returned data structure is consistent."""
result = gradio.get_processed_data(None, "", "", "")
# Check all required keys exist
required_keys = ["linkedin", "github", "job_post", "user_instructions", "errors"]
for key in required_keys:
self.assertIn(key, result)
# Check data types
self.assertIsInstance(result["errors"], list)
@patch('functions.gradio.extract_text_from_linkedin_pdf')
def test_linkedin_warning_status(self, mock_extract):
"""Test handling of LinkedIn warning status."""
mock_pdf = MagicMock()
mock_pdf.name = "test.pdf"
mock_extract.return_value = {
"status": "warning",
"message": "Some warning"
}
result = gradio.get_processed_data(mock_pdf, "", "", "")
# Warning status should not be treated as success
self.assertIsNone(result["linkedin"])
self.assertEqual(len(result["errors"]), 1)
self.assertIn("LinkedIn: Some warning", result["errors"])
def test_user_instructions_whitespace_handling(self):
"""Test user instructions whitespace handling."""
# Test with leading/trailing whitespace
result = gradio.get_processed_data(None, "", "", " Custom instructions ")
self.assertEqual(result["user_instructions"], "Custom instructions")
# Test with only whitespace
result = gradio.get_processed_data(None, "", "", " ")
self.assertIsNone(result["user_instructions"])
# Test with empty string
result = gradio.get_processed_data(None, "", "", "")
self.assertIsNone(result["user_instructions"])
if __name__ == '__main__':
unittest.main()