Spaces:
Configuration error
Configuration error
Updated and cleaned up gradio module unittests
Browse files- tests/test_gradio.py +175 -124
tests/test_gradio.py
CHANGED
@@ -3,285 +3,331 @@ Unit tests for the gradio module.
|
|
3 |
"""
|
4 |
|
5 |
import unittest
|
6 |
-
from unittest.mock import patch, MagicMock
|
7 |
-
import tempfile
|
8 |
-
import os
|
9 |
from functions import gradio
|
10 |
|
11 |
|
12 |
class TestProcessInputs(unittest.TestCase):
|
13 |
"""Test cases for the process_inputs function."""
|
14 |
-
|
15 |
def test_no_inputs_provided(self):
|
16 |
"""Test when no inputs are provided."""
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
25 |
def test_all_inputs_provided_success(self):
|
26 |
"""Test when all inputs are provided and successful."""
|
|
|
27 |
# Mock LinkedIn PDF file
|
28 |
mock_pdf = MagicMock()
|
29 |
mock_pdf.name = "test_resume.pdf"
|
30 |
-
|
31 |
# Mock successful extraction results
|
32 |
mock_linkedin_result = {
|
33 |
"status": "success",
|
34 |
"structured_text": {"sections": {}, "llm_formatted": "test content"},
|
35 |
"metadata": {"filename": "test_resume.pdf"}
|
36 |
}
|
37 |
-
|
38 |
mock_github_result = {
|
39 |
"status": "success",
|
40 |
"repositories": [{"name": "test-repo"}],
|
41 |
"metadata": {"username": "testuser"}
|
42 |
}
|
43 |
-
|
44 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
45 |
patch('functions.gradio.get_github_repositories') as mock_github, \
|
46 |
-
patch('functions.gradio.write_resume') as mock_write_resume
|
47 |
-
|
|
|
|
|
48 |
mock_linkedin.return_value = mock_linkedin_result
|
49 |
mock_github.return_value = mock_github_result
|
50 |
mock_write_resume.return_value = "Generated resume content"
|
51 |
-
|
|
|
52 |
result = gradio.process_inputs(
|
53 |
-
mock_pdf,
|
54 |
-
"https://github.com/testuser",
|
55 |
"Job posting text here",
|
56 |
"Please emphasize technical skills"
|
57 |
)
|
58 |
-
|
59 |
-
self.assertIn("β
LinkedIn Resume PDF
|
60 |
self.assertIn("β
Text extraction successful", result)
|
61 |
self.assertIn("β
GitHub Profile URL provided", result)
|
62 |
self.assertIn("β
GitHub list download successful", result)
|
63 |
self.assertIn("β
Job post text provided", result)
|
|
|
64 |
self.assertIn("β
Additional instructions provided", result)
|
65 |
self.assertIn("β
Resume generated successfully", result)
|
66 |
-
|
67 |
# Verify write_resume was called with user instructions
|
68 |
mock_write_resume.assert_called_with(mock_linkedin_result, "Please emphasize technical skills")
|
69 |
-
|
70 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
71 |
@patch('functions.gradio.write_resume')
|
72 |
def test_linkedin_extraction_failure(self, mock_write_resume, mock_extract):
|
73 |
"""Test LinkedIn PDF extraction failure."""
|
|
|
74 |
mock_pdf = MagicMock()
|
75 |
mock_pdf.name = "test_resume.pdf"
|
76 |
-
|
77 |
mock_extract.return_value = {
|
78 |
"status": "error",
|
79 |
"message": "Failed to read PDF"
|
80 |
}
|
81 |
mock_write_resume.return_value = "Generated resume content"
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
|
|
|
|
|
|
|
|
91 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
92 |
@patch('functions.gradio.write_resume')
|
93 |
def test_linkedin_extraction_warning(self, mock_write_resume, mock_extract):
|
94 |
"""Test LinkedIn PDF extraction warning."""
|
|
|
95 |
mock_pdf = MagicMock()
|
96 |
mock_pdf.name = "test_resume.pdf"
|
97 |
-
|
98 |
mock_extract.return_value = {
|
99 |
"status": "warning",
|
100 |
"message": "No text found in PDF"
|
101 |
}
|
102 |
mock_write_resume.return_value = "Generated resume content"
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
|
|
|
|
|
|
|
|
112 |
@patch('functions.gradio.get_github_repositories')
|
113 |
@patch('functions.gradio.write_resume')
|
114 |
def test_github_retrieval_failure(self, mock_write_resume, mock_github):
|
115 |
"""Test GitHub repository retrieval failure."""
|
|
|
116 |
mock_github.return_value = {
|
117 |
"status": "error",
|
118 |
"message": "User not found"
|
119 |
}
|
120 |
mock_write_resume.return_value = "Generated resume content"
|
121 |
-
|
122 |
result = gradio.process_inputs(None, "https://github.com/nonexistent", "", "")
|
123 |
-
|
124 |
self.assertIn("β
GitHub Profile URL provided", result)
|
125 |
self.assertIn("β GitHub extraction failed: User not found", result)
|
126 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
|
|
127 |
# Verify write_resume was NOT called since no LinkedIn data
|
128 |
mock_write_resume.assert_not_called()
|
129 |
-
|
130 |
def test_whitespace_only_inputs(self):
|
131 |
"""Test inputs with only whitespace."""
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
|
|
|
|
|
|
|
|
140 |
@patch('functions.gradio.write_resume')
|
141 |
-
|
|
|
|
|
142 |
"""Test job post with actual content."""
|
143 |
job_text = "Software Engineer position at Tech Company"
|
144 |
mock_write_resume.return_value = "Generated resume content"
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
153 |
@patch('functions.gradio.logger')
|
154 |
@patch('functions.gradio.write_resume')
|
155 |
def test_logging_calls(self, mock_write_resume, mock_logger):
|
|
|
156 |
"""Test that appropriate logging calls are made."""
|
157 |
mock_pdf = MagicMock()
|
158 |
mock_pdf.name = "test.pdf"
|
159 |
mock_write_resume.return_value = "Generated resume content"
|
160 |
-
|
161 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract, \
|
162 |
-
patch('functions.gradio.get_github_repositories') as mock_github
|
163 |
-
|
|
|
164 |
mock_extract.return_value = {"status": "success"}
|
165 |
mock_github.return_value = {"status": "success", "metadata": {"username": "test"}}
|
166 |
-
|
|
|
167 |
gradio.process_inputs(mock_pdf, "https://github.com/test", "job text", "custom instructions")
|
168 |
-
|
169 |
# Verify logging calls were made
|
170 |
mock_logger.info.assert_called()
|
171 |
-
|
172 |
@patch('functions.gradio.write_resume')
|
173 |
def test_user_instructions_with_content(self, mock_write_resume):
|
|
|
174 |
"""Test user instructions with actual content."""
|
175 |
instructions = "Please emphasize leadership skills and highlight remote work experience"
|
176 |
mock_write_resume.return_value = "Generated resume content"
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
|
|
|
|
|
|
185 |
@patch('functions.gradio.write_resume')
|
186 |
def test_user_instructions_empty(self, mock_write_resume):
|
|
|
187 |
"""Test user instructions when empty."""
|
188 |
mock_write_resume.return_value = "Generated resume content"
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
|
|
|
|
196 |
|
197 |
|
198 |
class TestGetProcessedData(unittest.TestCase):
|
199 |
"""Test cases for the get_processed_data function."""
|
200 |
-
|
201 |
def test_no_inputs(self):
|
202 |
"""Test with no inputs provided."""
|
|
|
203 |
result = gradio.get_processed_data(None, "", "", "")
|
204 |
-
|
205 |
self.assertIsNone(result["linkedin"])
|
206 |
self.assertIsNone(result["github"])
|
207 |
self.assertIsNone(result["job_post"])
|
208 |
self.assertIsNone(result["user_instructions"])
|
209 |
self.assertEqual(len(result["errors"]), 0)
|
210 |
-
|
211 |
def test_all_successful_inputs(self):
|
212 |
"""Test with all successful inputs."""
|
|
|
213 |
mock_pdf = MagicMock()
|
214 |
mock_pdf.name = "test.pdf"
|
215 |
-
|
216 |
mock_linkedin_result = {
|
217 |
"status": "success",
|
218 |
"structured_text": {"sections": {}, "llm_formatted": "content"}
|
219 |
}
|
220 |
-
|
221 |
mock_github_result = {
|
222 |
"status": "success",
|
223 |
"repositories": [{"name": "repo"}],
|
224 |
"metadata": {"username": "user"}
|
225 |
}
|
226 |
-
|
227 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
228 |
patch('functions.gradio.get_github_repositories') as mock_github:
|
229 |
-
|
230 |
mock_linkedin.return_value = mock_linkedin_result
|
231 |
mock_github.return_value = mock_github_result
|
232 |
-
|
233 |
result = gradio.get_processed_data(
|
234 |
mock_pdf,
|
235 |
"https://github.com/user",
|
236 |
"Job posting content",
|
237 |
"Custom instructions"
|
238 |
)
|
239 |
-
|
240 |
self.assertEqual(result["linkedin"], mock_linkedin_result)
|
241 |
self.assertEqual(result["github"], mock_github_result)
|
242 |
self.assertEqual(result["job_post"], "Job posting content")
|
243 |
self.assertEqual(result["user_instructions"], "Custom instructions")
|
244 |
self.assertEqual(len(result["errors"]), 0)
|
245 |
-
|
246 |
def test_linkedin_error(self):
|
247 |
"""Test with LinkedIn processing error."""
|
|
|
248 |
mock_pdf = MagicMock()
|
249 |
mock_pdf.name = "test.pdf"
|
250 |
-
|
251 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract:
|
252 |
mock_extract.return_value = {
|
253 |
"status": "error",
|
254 |
"message": "PDF read failed"
|
255 |
}
|
256 |
-
|
257 |
result = gradio.get_processed_data(mock_pdf, "", "", "")
|
258 |
-
|
259 |
self.assertIsNone(result["linkedin"])
|
260 |
self.assertEqual(len(result["errors"]), 1)
|
261 |
self.assertIn("LinkedIn: PDF read failed", result["errors"])
|
262 |
-
|
263 |
def test_github_error(self):
|
264 |
"""Test with GitHub processing error."""
|
|
|
265 |
with patch('functions.gradio.get_github_repositories') as mock_github:
|
266 |
mock_github.return_value = {
|
267 |
"status": "error",
|
268 |
"message": "User not found"
|
269 |
}
|
270 |
-
|
271 |
result = gradio.get_processed_data(None, "https://github.com/invalid", "", "")
|
272 |
-
|
273 |
self.assertIsNone(result["github"])
|
274 |
self.assertEqual(len(result["errors"]), 1)
|
275 |
self.assertIn("GitHub: User not found", result["errors"])
|
276 |
-
|
277 |
def test_multiple_errors(self):
|
278 |
"""Test with multiple processing errors."""
|
|
|
279 |
mock_pdf = MagicMock()
|
280 |
mock_pdf.name = "test.pdf"
|
281 |
-
|
282 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
283 |
patch('functions.gradio.get_github_repositories') as mock_github:
|
284 |
-
|
285 |
mock_linkedin.return_value = {
|
286 |
"status": "error",
|
287 |
"message": "LinkedIn error"
|
@@ -290,88 +336,93 @@ class TestGetProcessedData(unittest.TestCase):
|
|
290 |
"status": "error",
|
291 |
"message": "GitHub error"
|
292 |
}
|
293 |
-
|
294 |
result = gradio.get_processed_data(
|
295 |
mock_pdf,
|
296 |
"https://github.com/user",
|
297 |
"",
|
298 |
""
|
299 |
)
|
300 |
-
|
301 |
self.assertIsNone(result["linkedin"])
|
302 |
self.assertIsNone(result["github"])
|
303 |
self.assertEqual(len(result["errors"]), 2)
|
304 |
self.assertIn("LinkedIn: LinkedIn error", result["errors"])
|
305 |
self.assertIn("GitHub: GitHub error", result["errors"])
|
306 |
-
|
307 |
def test_job_post_whitespace_handling(self):
|
308 |
"""Test job post whitespace handling."""
|
|
|
309 |
# Test with leading/trailing whitespace
|
310 |
result = gradio.get_processed_data(None, "", " Job content ", "")
|
311 |
self.assertEqual(result["job_post"], "Job content")
|
312 |
-
|
313 |
# Test with only whitespace
|
314 |
result = gradio.get_processed_data(None, "", " ", "")
|
315 |
self.assertIsNone(result["job_post"])
|
316 |
-
|
317 |
# Test with empty string
|
318 |
result = gradio.get_processed_data(None, "", "", "")
|
319 |
self.assertIsNone(result["job_post"])
|
320 |
-
|
321 |
def test_github_url_whitespace_handling(self):
|
322 |
"""Test GitHub URL whitespace handling."""
|
|
|
323 |
with patch('functions.gradio.get_github_repositories') as mock_github:
|
324 |
mock_github.return_value = {"status": "success", "repositories": []}
|
325 |
-
|
326 |
# Test with leading/trailing whitespace
|
327 |
-
|
328 |
mock_github.assert_called_with(" https://github.com/user ")
|
329 |
-
|
330 |
# Test with only whitespace - should not call function
|
331 |
mock_github.reset_mock()
|
332 |
-
|
333 |
mock_github.assert_not_called()
|
334 |
-
|
335 |
def test_data_structure_consistency(self):
|
336 |
"""Test that returned data structure is consistent."""
|
|
|
337 |
result = gradio.get_processed_data(None, "", "", "")
|
338 |
-
|
339 |
# Check all required keys exist
|
340 |
required_keys = ["linkedin", "github", "job_post", "user_instructions", "errors"]
|
341 |
for key in required_keys:
|
342 |
self.assertIn(key, result)
|
343 |
-
|
344 |
# Check data types
|
345 |
self.assertIsInstance(result["errors"], list)
|
346 |
-
|
347 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
348 |
def test_linkedin_warning_status(self, mock_extract):
|
349 |
"""Test handling of LinkedIn warning status."""
|
|
|
350 |
mock_pdf = MagicMock()
|
351 |
mock_pdf.name = "test.pdf"
|
352 |
-
|
353 |
mock_extract.return_value = {
|
354 |
"status": "warning",
|
355 |
"message": "Some warning"
|
356 |
}
|
357 |
-
|
358 |
result = gradio.get_processed_data(mock_pdf, "", "", "")
|
359 |
-
|
360 |
# Warning status should not be treated as success
|
361 |
self.assertIsNone(result["linkedin"])
|
362 |
self.assertEqual(len(result["errors"]), 1)
|
363 |
self.assertIn("LinkedIn: Some warning", result["errors"])
|
364 |
-
|
365 |
def test_user_instructions_whitespace_handling(self):
|
366 |
"""Test user instructions whitespace handling."""
|
|
|
367 |
# Test with leading/trailing whitespace
|
368 |
result = gradio.get_processed_data(None, "", "", " Custom instructions ")
|
369 |
self.assertEqual(result["user_instructions"], "Custom instructions")
|
370 |
-
|
371 |
# Test with only whitespace
|
372 |
result = gradio.get_processed_data(None, "", "", " ")
|
373 |
self.assertIsNone(result["user_instructions"])
|
374 |
-
|
375 |
# Test with empty string
|
376 |
result = gradio.get_processed_data(None, "", "", "")
|
377 |
self.assertIsNone(result["user_instructions"])
|
|
|
3 |
"""
|
4 |
|
5 |
import unittest
|
6 |
+
from unittest.mock import patch, MagicMock
|
|
|
|
|
7 |
from functions import gradio
|
8 |
|
9 |
|
10 |
class TestProcessInputs(unittest.TestCase):
|
11 |
"""Test cases for the process_inputs function."""
|
12 |
+
|
13 |
def test_no_inputs_provided(self):
|
14 |
"""Test when no inputs are provided."""
|
15 |
+
|
16 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
17 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
18 |
+
|
19 |
+
result = gradio.process_inputs(None, "", "", "")
|
20 |
+
|
21 |
+
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
22 |
+
self.assertIn("β
Using default GitHub Profile URL", result)
|
23 |
+
self.assertIn("β Job post not provided", result)
|
24 |
+
self.assertIn("βΉοΈ No additional instructions provided", result)
|
25 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
26 |
+
|
27 |
def test_all_inputs_provided_success(self):
|
28 |
"""Test when all inputs are provided and successful."""
|
29 |
+
|
30 |
# Mock LinkedIn PDF file
|
31 |
mock_pdf = MagicMock()
|
32 |
mock_pdf.name = "test_resume.pdf"
|
33 |
+
|
34 |
# Mock successful extraction results
|
35 |
mock_linkedin_result = {
|
36 |
"status": "success",
|
37 |
"structured_text": {"sections": {}, "llm_formatted": "test content"},
|
38 |
"metadata": {"filename": "test_resume.pdf"}
|
39 |
}
|
40 |
+
|
41 |
mock_github_result = {
|
42 |
"status": "success",
|
43 |
"repositories": [{"name": "test-repo"}],
|
44 |
"metadata": {"username": "testuser"}
|
45 |
}
|
46 |
+
|
47 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
48 |
patch('functions.gradio.get_github_repositories') as mock_github, \
|
49 |
+
patch('functions.gradio.write_resume') as mock_write_resume, \
|
50 |
+
patch('functions.gradio.summarize_job_call') as mock_summarize: #, \
|
51 |
+
#patch('functions.gradio.shutil.copy2') as mock_copy:
|
52 |
+
|
53 |
mock_linkedin.return_value = mock_linkedin_result
|
54 |
mock_github.return_value = mock_github_result
|
55 |
mock_write_resume.return_value = "Generated resume content"
|
56 |
+
mock_summarize.return_value = "Job summary content\n"
|
57 |
+
|
58 |
result = gradio.process_inputs(
|
59 |
+
mock_pdf,
|
60 |
+
"https://github.com/testuser",
|
61 |
"Job posting text here",
|
62 |
"Please emphasize technical skills"
|
63 |
)
|
64 |
+
|
65 |
+
self.assertIn("β
LinkedIn Resume PDF provided", result)
|
66 |
self.assertIn("β
Text extraction successful", result)
|
67 |
self.assertIn("β
GitHub Profile URL provided", result)
|
68 |
self.assertIn("β
GitHub list download successful", result)
|
69 |
self.assertIn("β
Job post text provided", result)
|
70 |
+
self.assertIn("β
Job post summary generated", result)
|
71 |
self.assertIn("β
Additional instructions provided", result)
|
72 |
self.assertIn("β
Resume generated successfully", result)
|
73 |
+
|
74 |
# Verify write_resume was called with user instructions
|
75 |
mock_write_resume.assert_called_with(mock_linkedin_result, "Please emphasize technical skills")
|
76 |
+
|
77 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
78 |
@patch('functions.gradio.write_resume')
|
79 |
def test_linkedin_extraction_failure(self, mock_write_resume, mock_extract):
|
80 |
"""Test LinkedIn PDF extraction failure."""
|
81 |
+
|
82 |
mock_pdf = MagicMock()
|
83 |
mock_pdf.name = "test_resume.pdf"
|
84 |
+
|
85 |
mock_extract.return_value = {
|
86 |
"status": "error",
|
87 |
"message": "Failed to read PDF"
|
88 |
}
|
89 |
mock_write_resume.return_value = "Generated resume content"
|
90 |
+
|
91 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
92 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
93 |
+
|
94 |
+
result = gradio.process_inputs(mock_pdf, "", "", "")
|
95 |
+
|
96 |
+
self.assertIn("β
LinkedIn Resume PDF provided", result)
|
97 |
+
self.assertIn("β Text extraction failed: Failed to read PDF", result)
|
98 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
99 |
+
|
100 |
+
# Verify write_resume was NOT called since extraction failed
|
101 |
+
mock_write_resume.assert_not_called()
|
102 |
+
|
103 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
104 |
@patch('functions.gradio.write_resume')
|
105 |
def test_linkedin_extraction_warning(self, mock_write_resume, mock_extract):
|
106 |
"""Test LinkedIn PDF extraction warning."""
|
107 |
+
|
108 |
mock_pdf = MagicMock()
|
109 |
mock_pdf.name = "test_resume.pdf"
|
110 |
+
|
111 |
mock_extract.return_value = {
|
112 |
"status": "warning",
|
113 |
"message": "No text found in PDF"
|
114 |
}
|
115 |
mock_write_resume.return_value = "Generated resume content"
|
116 |
+
|
117 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
118 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
119 |
+
|
120 |
+
result = gradio.process_inputs(mock_pdf, "", "", "")
|
121 |
+
|
122 |
+
self.assertIn("β
LinkedIn Resume PDF provided", result)
|
123 |
+
self.assertIn("β οΈ Text extraction: No text found in PDF", result)
|
124 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
125 |
+
|
126 |
+
# Verify write_resume was NOT called since extraction had warning status
|
127 |
+
mock_write_resume.assert_not_called()
|
128 |
+
|
129 |
@patch('functions.gradio.get_github_repositories')
|
130 |
@patch('functions.gradio.write_resume')
|
131 |
def test_github_retrieval_failure(self, mock_write_resume, mock_github):
|
132 |
"""Test GitHub repository retrieval failure."""
|
133 |
+
|
134 |
mock_github.return_value = {
|
135 |
"status": "error",
|
136 |
"message": "User not found"
|
137 |
}
|
138 |
mock_write_resume.return_value = "Generated resume content"
|
139 |
+
|
140 |
result = gradio.process_inputs(None, "https://github.com/nonexistent", "", "")
|
141 |
+
|
142 |
self.assertIn("β
GitHub Profile URL provided", result)
|
143 |
self.assertIn("β GitHub extraction failed: User not found", result)
|
144 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
145 |
+
|
146 |
# Verify write_resume was NOT called since no LinkedIn data
|
147 |
mock_write_resume.assert_not_called()
|
148 |
+
|
149 |
def test_whitespace_only_inputs(self):
|
150 |
"""Test inputs with only whitespace."""
|
151 |
+
|
152 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
153 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
154 |
+
|
155 |
+
result = gradio.process_inputs(None, " ", " ", " ")
|
156 |
+
|
157 |
+
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
158 |
+
self.assertIn("β
Using default GitHub Profile URL", result)
|
159 |
+
self.assertIn("β Job post not provided", result)
|
160 |
+
self.assertIn("βΉοΈ No additional instructions provided", result)
|
161 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
162 |
+
|
163 |
@patch('functions.gradio.write_resume')
|
164 |
+
@patch('functions.gradio.summarize_job_call')
|
165 |
+
def test_job_post_with_content(self, mock_summarize, mock_write_resume):
|
166 |
+
|
167 |
"""Test job post with actual content."""
|
168 |
job_text = "Software Engineer position at Tech Company"
|
169 |
mock_write_resume.return_value = "Generated resume content"
|
170 |
+
mock_summarize.return_value = "Job summary content\n"
|
171 |
+
|
172 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
173 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
174 |
+
|
175 |
+
result = gradio.process_inputs(None, "", job_text, "")
|
176 |
+
|
177 |
+
self.assertIn("β
Job post text provided", result)
|
178 |
+
self.assertIn("β
Job post summary generated", result)
|
179 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
180 |
+
# Verify write_resume was NOT called since no LinkedIn data
|
181 |
+
mock_write_resume.assert_not_called()
|
182 |
+
|
183 |
@patch('functions.gradio.logger')
|
184 |
@patch('functions.gradio.write_resume')
|
185 |
def test_logging_calls(self, mock_write_resume, mock_logger):
|
186 |
+
|
187 |
"""Test that appropriate logging calls are made."""
|
188 |
mock_pdf = MagicMock()
|
189 |
mock_pdf.name = "test.pdf"
|
190 |
mock_write_resume.return_value = "Generated resume content"
|
191 |
+
|
192 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract, \
|
193 |
+
patch('functions.gradio.get_github_repositories') as mock_github, \
|
194 |
+
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
195 |
+
|
196 |
mock_extract.return_value = {"status": "success"}
|
197 |
mock_github.return_value = {"status": "success", "metadata": {"username": "test"}}
|
198 |
+
mock_summarize.return_value = "Job summary\n"
|
199 |
+
|
200 |
gradio.process_inputs(mock_pdf, "https://github.com/test", "job text", "custom instructions")
|
201 |
+
|
202 |
# Verify logging calls were made
|
203 |
mock_logger.info.assert_called()
|
204 |
+
|
205 |
@patch('functions.gradio.write_resume')
|
206 |
def test_user_instructions_with_content(self, mock_write_resume):
|
207 |
+
|
208 |
"""Test user instructions with actual content."""
|
209 |
instructions = "Please emphasize leadership skills and highlight remote work experience"
|
210 |
mock_write_resume.return_value = "Generated resume content"
|
211 |
+
|
212 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
213 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
214 |
+
|
215 |
+
result = gradio.process_inputs(None, "", "", instructions)
|
216 |
+
|
217 |
+
self.assertIn("β
Additional instructions provided", result)
|
218 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
219 |
+
# Verify write_resume was NOT called since no valid extraction result
|
220 |
+
mock_write_resume.assert_not_called()
|
221 |
+
|
222 |
@patch('functions.gradio.write_resume')
|
223 |
def test_user_instructions_empty(self, mock_write_resume):
|
224 |
+
|
225 |
"""Test user instructions when empty."""
|
226 |
mock_write_resume.return_value = "Generated resume content"
|
227 |
+
|
228 |
+
with patch('functions.gradio.get_github_repositories') as mock_github:
|
229 |
+
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
230 |
+
|
231 |
+
result = gradio.process_inputs(None, "", "", "")
|
232 |
+
|
233 |
+
self.assertIn("βΉοΈ No additional instructions provided", result)
|
234 |
+
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
235 |
+
# Verify write_resume was NOT called since no valid extraction result
|
236 |
+
mock_write_resume.assert_not_called()
|
237 |
|
238 |
|
239 |
class TestGetProcessedData(unittest.TestCase):
|
240 |
"""Test cases for the get_processed_data function."""
|
241 |
+
|
242 |
def test_no_inputs(self):
|
243 |
"""Test with no inputs provided."""
|
244 |
+
|
245 |
result = gradio.get_processed_data(None, "", "", "")
|
246 |
+
|
247 |
self.assertIsNone(result["linkedin"])
|
248 |
self.assertIsNone(result["github"])
|
249 |
self.assertIsNone(result["job_post"])
|
250 |
self.assertIsNone(result["user_instructions"])
|
251 |
self.assertEqual(len(result["errors"]), 0)
|
252 |
+
|
253 |
def test_all_successful_inputs(self):
|
254 |
"""Test with all successful inputs."""
|
255 |
+
|
256 |
mock_pdf = MagicMock()
|
257 |
mock_pdf.name = "test.pdf"
|
258 |
+
|
259 |
mock_linkedin_result = {
|
260 |
"status": "success",
|
261 |
"structured_text": {"sections": {}, "llm_formatted": "content"}
|
262 |
}
|
263 |
+
|
264 |
mock_github_result = {
|
265 |
"status": "success",
|
266 |
"repositories": [{"name": "repo"}],
|
267 |
"metadata": {"username": "user"}
|
268 |
}
|
269 |
+
|
270 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
271 |
patch('functions.gradio.get_github_repositories') as mock_github:
|
272 |
+
|
273 |
mock_linkedin.return_value = mock_linkedin_result
|
274 |
mock_github.return_value = mock_github_result
|
275 |
+
|
276 |
result = gradio.get_processed_data(
|
277 |
mock_pdf,
|
278 |
"https://github.com/user",
|
279 |
"Job posting content",
|
280 |
"Custom instructions"
|
281 |
)
|
282 |
+
|
283 |
self.assertEqual(result["linkedin"], mock_linkedin_result)
|
284 |
self.assertEqual(result["github"], mock_github_result)
|
285 |
self.assertEqual(result["job_post"], "Job posting content")
|
286 |
self.assertEqual(result["user_instructions"], "Custom instructions")
|
287 |
self.assertEqual(len(result["errors"]), 0)
|
288 |
+
|
289 |
def test_linkedin_error(self):
|
290 |
"""Test with LinkedIn processing error."""
|
291 |
+
|
292 |
mock_pdf = MagicMock()
|
293 |
mock_pdf.name = "test.pdf"
|
294 |
+
|
295 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_extract:
|
296 |
mock_extract.return_value = {
|
297 |
"status": "error",
|
298 |
"message": "PDF read failed"
|
299 |
}
|
300 |
+
|
301 |
result = gradio.get_processed_data(mock_pdf, "", "", "")
|
302 |
+
|
303 |
self.assertIsNone(result["linkedin"])
|
304 |
self.assertEqual(len(result["errors"]), 1)
|
305 |
self.assertIn("LinkedIn: PDF read failed", result["errors"])
|
306 |
+
|
307 |
def test_github_error(self):
|
308 |
"""Test with GitHub processing error."""
|
309 |
+
|
310 |
with patch('functions.gradio.get_github_repositories') as mock_github:
|
311 |
mock_github.return_value = {
|
312 |
"status": "error",
|
313 |
"message": "User not found"
|
314 |
}
|
315 |
+
|
316 |
result = gradio.get_processed_data(None, "https://github.com/invalid", "", "")
|
317 |
+
|
318 |
self.assertIsNone(result["github"])
|
319 |
self.assertEqual(len(result["errors"]), 1)
|
320 |
self.assertIn("GitHub: User not found", result["errors"])
|
321 |
+
|
322 |
def test_multiple_errors(self):
|
323 |
"""Test with multiple processing errors."""
|
324 |
+
|
325 |
mock_pdf = MagicMock()
|
326 |
mock_pdf.name = "test.pdf"
|
327 |
+
|
328 |
with patch('functions.gradio.extract_text_from_linkedin_pdf') as mock_linkedin, \
|
329 |
patch('functions.gradio.get_github_repositories') as mock_github:
|
330 |
+
|
331 |
mock_linkedin.return_value = {
|
332 |
"status": "error",
|
333 |
"message": "LinkedIn error"
|
|
|
336 |
"status": "error",
|
337 |
"message": "GitHub error"
|
338 |
}
|
339 |
+
|
340 |
result = gradio.get_processed_data(
|
341 |
mock_pdf,
|
342 |
"https://github.com/user",
|
343 |
"",
|
344 |
""
|
345 |
)
|
346 |
+
|
347 |
self.assertIsNone(result["linkedin"])
|
348 |
self.assertIsNone(result["github"])
|
349 |
self.assertEqual(len(result["errors"]), 2)
|
350 |
self.assertIn("LinkedIn: LinkedIn error", result["errors"])
|
351 |
self.assertIn("GitHub: GitHub error", result["errors"])
|
352 |
+
|
353 |
def test_job_post_whitespace_handling(self):
|
354 |
"""Test job post whitespace handling."""
|
355 |
+
|
356 |
# Test with leading/trailing whitespace
|
357 |
result = gradio.get_processed_data(None, "", " Job content ", "")
|
358 |
self.assertEqual(result["job_post"], "Job content")
|
359 |
+
|
360 |
# Test with only whitespace
|
361 |
result = gradio.get_processed_data(None, "", " ", "")
|
362 |
self.assertIsNone(result["job_post"])
|
363 |
+
|
364 |
# Test with empty string
|
365 |
result = gradio.get_processed_data(None, "", "", "")
|
366 |
self.assertIsNone(result["job_post"])
|
367 |
+
|
368 |
def test_github_url_whitespace_handling(self):
|
369 |
"""Test GitHub URL whitespace handling."""
|
370 |
+
|
371 |
with patch('functions.gradio.get_github_repositories') as mock_github:
|
372 |
mock_github.return_value = {"status": "success", "repositories": []}
|
373 |
+
|
374 |
# Test with leading/trailing whitespace
|
375 |
+
_ = gradio.get_processed_data(None, " https://github.com/user ", "", "")
|
376 |
mock_github.assert_called_with(" https://github.com/user ")
|
377 |
+
|
378 |
# Test with only whitespace - should not call function
|
379 |
mock_github.reset_mock()
|
380 |
+
_ = gradio.get_processed_data(None, " ", "", "")
|
381 |
mock_github.assert_not_called()
|
382 |
+
|
383 |
def test_data_structure_consistency(self):
|
384 |
"""Test that returned data structure is consistent."""
|
385 |
+
|
386 |
result = gradio.get_processed_data(None, "", "", "")
|
387 |
+
|
388 |
# Check all required keys exist
|
389 |
required_keys = ["linkedin", "github", "job_post", "user_instructions", "errors"]
|
390 |
for key in required_keys:
|
391 |
self.assertIn(key, result)
|
392 |
+
|
393 |
# Check data types
|
394 |
self.assertIsInstance(result["errors"], list)
|
395 |
+
|
396 |
@patch('functions.gradio.extract_text_from_linkedin_pdf')
|
397 |
def test_linkedin_warning_status(self, mock_extract):
|
398 |
"""Test handling of LinkedIn warning status."""
|
399 |
+
|
400 |
mock_pdf = MagicMock()
|
401 |
mock_pdf.name = "test.pdf"
|
402 |
+
|
403 |
mock_extract.return_value = {
|
404 |
"status": "warning",
|
405 |
"message": "Some warning"
|
406 |
}
|
407 |
+
|
408 |
result = gradio.get_processed_data(mock_pdf, "", "", "")
|
409 |
+
|
410 |
# Warning status should not be treated as success
|
411 |
self.assertIsNone(result["linkedin"])
|
412 |
self.assertEqual(len(result["errors"]), 1)
|
413 |
self.assertIn("LinkedIn: Some warning", result["errors"])
|
414 |
+
|
415 |
def test_user_instructions_whitespace_handling(self):
|
416 |
"""Test user instructions whitespace handling."""
|
417 |
+
|
418 |
# Test with leading/trailing whitespace
|
419 |
result = gradio.get_processed_data(None, "", "", " Custom instructions ")
|
420 |
self.assertEqual(result["user_instructions"], "Custom instructions")
|
421 |
+
|
422 |
# Test with only whitespace
|
423 |
result = gradio.get_processed_data(None, "", "", " ")
|
424 |
self.assertIsNone(result["user_instructions"])
|
425 |
+
|
426 |
# Test with empty string
|
427 |
result = gradio.get_processed_data(None, "", "", "")
|
428 |
self.assertIsNone(result["user_instructions"])
|