gperdrizet commited on
Commit
e20dc23
Β·
verified Β·
1 Parent(s): 123b1a6

Updated and cleaned up gradio module unittests

Browse files
Files changed (1) hide show
  1. 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, mock_open
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
- result = gradio.process_inputs(None, "", "", "")
18
-
19
- self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
20
- self.assertIn("❌ No GitHub profile URL provided", result)
21
- self.assertIn("❌ Job post not provided", result)
22
- self.assertIn("ℹ️ No additional instructions provided", result)
23
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
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 uploaded", result)
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
- result = gradio.process_inputs(mock_pdf, "", "", "")
84
-
85
- self.assertIn("βœ… LinkedIn Resume PDF uploaded", result)
86
- self.assertIn("❌ Text extraction failed: Failed to read PDF", result)
87
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
88
- # Verify write_resume was NOT called since extraction failed
89
- mock_write_resume.assert_not_called()
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
- result = gradio.process_inputs(mock_pdf, "", "", "")
105
-
106
- self.assertIn("βœ… LinkedIn Resume PDF uploaded", result)
107
- self.assertIn("⚠️ Text extraction: No text found in PDF", result)
108
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
109
- # Verify write_resume was NOT called since extraction had warning status
110
- mock_write_resume.assert_not_called()
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
- result = gradio.process_inputs(None, " ", " ", " ")
133
-
134
- self.assertIn("❌ No LinkedIn resume PDF file uploaded", result)
135
- self.assertIn("❌ No GitHub profile URL provided", result)
136
- self.assertIn("❌ Job post not provided", result)
137
- self.assertIn("ℹ️ No additional instructions provided", result)
138
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
139
-
 
 
 
 
140
  @patch('functions.gradio.write_resume')
141
- def test_job_post_with_content(self, mock_write_resume):
 
 
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
- result = gradio.process_inputs(None, "", job_text, "")
147
-
148
- self.assertIn("βœ… Job post text provided", result)
149
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
150
- # Verify write_resume was NOT called since no LinkedIn data
151
- mock_write_resume.assert_not_called()
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
- result = gradio.process_inputs(None, "", "", instructions)
179
-
180
- self.assertIn("βœ… Additional instructions provided", result)
181
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
182
- # Verify write_resume was NOT called since no valid extraction result
183
- mock_write_resume.assert_not_called()
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
- result = gradio.process_inputs(None, "", "", "")
191
-
192
- self.assertIn("ℹ️ No additional instructions provided", result)
193
- self.assertIn("❌ Cannot generate resume: No valid LinkedIn data extracted", result)
194
- # Verify write_resume was NOT called since no valid extraction result
195
- mock_write_resume.assert_not_called()
 
 
 
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
- result = gradio.get_processed_data(None, " https://github.com/user ", "", "")
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
- result = gradio.get_processed_data(None, " ", "", "")
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"])