resumate / tests /test_gradio.py
gperdrizet's picture
Added mocking for other API calls
de5f555 verified
raw
history blame
22.8 kB
"""
Unit tests for the gradio module.
"""
import unittest
from unittest.mock import patch, MagicMock
from functions import gradio
class TestProcessInputs(unittest.TestCase):
"""Test cases for the process_inputs function."""
@patch('functions.gradio.load_default_job_call')
def test_no_inputs_provided(self, mock_load_default):
"""Test when no inputs are provided and default job is available."""
# Mock default job call loading to return content
mock_load_default.return_value = "Default job content from sample_job.txt"
with patch('functions.gradio.get_github_repositories') as mock_github, \
patch('functions.gradio.summarize_job_call') as mock_summarize:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
mock_summarize.return_value = "Mocked job summary"
result = gradio.process_inputs(None, "", "", "")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("βœ… Using default GitHub Profile URL", result)
self.assertIn("ℹ️ No job post provided, attempting to use default", result)
self.assertIn("βœ… Using default job post", result)
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
@patch('functions.gradio.load_default_job_call')
def test_no_inputs_no_default_job(self, mock_load_default):
"""Test when no inputs are provided and no default job is available."""
# Mock default job call loading to return None (no default available)
mock_load_default.return_value = None
with patch('functions.gradio.get_github_repositories') as mock_github, \
patch('functions.gradio.summarize_job_call') as mock_summarize:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
mock_summarize.return_value = None # No summarization since no job post
result = gradio.process_inputs(None, "", "", "")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("βœ… Using default GitHub Profile URL", result)
self.assertIn("ℹ️ No job post provided, attempting to use default", result)
self.assertIn("ℹ️ No default job post available, proceeding without job post", result)
self.assertIn("ℹ️ Proceeding without job post analysis", 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, \
patch('functions.gradio.summarize_job_call') as mock_summarize: #, \
#patch('functions.gradio.shutil.copy2') as mock_copy:
mock_linkedin.return_value = mock_linkedin_result
mock_github.return_value = mock_github_result
mock_write_resume.return_value = "Generated resume content"
mock_summarize.return_value = "Job summary content\n"
result = gradio.process_inputs(
mock_pdf,
"https://github.com/testuser",
"Job posting text here",
"Please emphasize technical skills"
)
self.assertIn("βœ… LinkedIn Resume PDF provided", 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("βœ… Job post summary generated", result)
self.assertIn("βœ… Additional instructions provided", result)
self.assertIn("βœ… Resume generated successfully", result)
# Verify write_resume was called with user instructions and job summary
mock_write_resume.assert_called_with(
mock_linkedin_result,
"Please emphasize technical skills",
"Job summary content\n"
)
@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"
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
result = gradio.process_inputs(mock_pdf, "", "", "")
self.assertIn("βœ… LinkedIn Resume PDF provided", 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"
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
result = gradio.process_inputs(mock_pdf, "", "", "")
self.assertIn("βœ… LinkedIn Resume PDF provided", 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()
@patch('functions.gradio.load_default_job_call')
def test_whitespace_only_inputs(self, mock_load_default):
"""Test inputs with only whitespace and default job available."""
# Mock default job call loading to return content
mock_load_default.return_value = "Default job content from sample_job.txt"
with patch('functions.gradio.get_github_repositories') as mock_github, \
patch('functions.gradio.summarize_job_call') as mock_summarize:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
mock_summarize.return_value = "Mocked job summary"
result = gradio.process_inputs(None, " ", " ", " ")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("βœ… Using default GitHub Profile URL", result)
self.assertIn("ℹ️ No job post provided, attempting to use default", result)
self.assertIn("βœ… Using default job post", result)
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
@patch('functions.gradio.load_default_job_call')
def test_whitespace_only_inputs_no_default(self, mock_load_default):
"""Test inputs with only whitespace and no default job available."""
# Mock default job call loading to return None
mock_load_default.return_value = None
with patch('functions.gradio.get_github_repositories') as mock_github, \
patch('functions.gradio.summarize_job_call') as mock_summarize:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
mock_summarize.return_value = None # No summarization since no job post
result = gradio.process_inputs(None, " ", " ", " ")
self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
self.assertIn("βœ… Using default GitHub Profile URL", result)
self.assertIn("ℹ️ No job post provided, attempting to use default", result)
self.assertIn("ℹ️ No default job post available, proceeding without job post", result)
self.assertIn("ℹ️ Proceeding without job post analysis", result)
self.assertIn("ℹ️ No additional instructions provided", result)
self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
@patch('functions.gradio.write_resume')
@patch('functions.gradio.summarize_job_call')
def test_job_post_with_content(self, mock_summarize, 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"
mock_summarize.return_value = "Job summary content\n"
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
result = gradio.process_inputs(None, "", job_text, "")
self.assertIn("βœ… Job post text provided", result)
self.assertIn("βœ… Job post summary generated", 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, \
patch('functions.gradio.summarize_job_call') as mock_summarize:
mock_extract.return_value = {"status": "success"}
mock_github.return_value = {"status": "success", "metadata": {"username": "test"}}
mock_summarize.return_value = "Job summary\n"
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"
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
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"
with patch('functions.gradio.get_github_repositories') as mock_github:
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
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."""
@patch('functions.gradio.load_default_job_call')
def test_no_inputs(self, mock_load_default):
"""Test with no inputs provided."""
# Mock the default job call loading
mock_load_default.return_value = "Default job call content from sample_job.txt"
result = gradio.get_processed_data(None, "", "", "")
self.assertIsNone(result["linkedin"])
self.assertIsNone(result["github"])
self.assertEqual(result["job_post"], "Default job call content from sample_job.txt")
self.assertIsNone(result["user_instructions"])
self.assertEqual(len(result["errors"]), 0)
@patch('functions.gradio.load_default_job_call')
def test_no_inputs_no_default_job(self, mock_load_default):
"""Test with no inputs provided and no default job available."""
# Mock the default job call loading to return None
mock_load_default.return_value = None
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"])
@patch('functions.gradio.load_default_job_call')
def test_job_post_whitespace_handling(self, mock_load_default):
"""Test job post whitespace handling."""
# Mock the default job call loading
mock_load_default.return_value = "Default job content"
# Test with leading/trailing whitespace
result = gradio.get_processed_data(None, "", " Job content ", "")
self.assertEqual(result["job_post"], "Job content")
# Test with only whitespace - should load default
result = gradio.get_processed_data(None, "", " ", "")
self.assertEqual(result["job_post"], "Default job content")
# Test with empty string - should load default
result = gradio.get_processed_data(None, "", "", "")
self.assertEqual(result["job_post"], "Default job content")
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
_ = 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()
_ = 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()