@@ -365,6 +365,71 @@ def test_get_per_issue_metrics_with_ignore_users(self):
365365 expected_issues_with_metrics [0 ].time_to_close ,
366366 )
367367
368+ @patch .dict (
369+ os .environ ,
370+ {
371+ "GH_TOKEN" : "test_token" ,
372+ "SEARCH_QUERY" : "is:pr is:open repo:user/repo" ,
373+ },
374+ )
375+ def test_get_per_issue_metrics_with_ghost_user_pull_request (self ):
376+ """
377+ Test that the function handles TypeError when a pull request
378+ contains a ghost user (deleted account) gracefully.
379+ """
380+ # Create mock data for a pull request that will cause TypeError on pull_request()
381+ mock_issue = MagicMock (
382+ title = "PR with Ghost User" ,
383+ html_url = "https://github.com/user/repo/pull/1" ,
384+ user = {"login" : "existing_user" },
385+ state = "open" ,
386+ comments = 0 ,
387+ created_at = "2023-01-01T00:00:00Z" ,
388+ closed_at = None ,
389+ )
390+
391+ # Mock the issue to have pull_request_urls (indicating it's a PR)
392+ mock_issue .issue .pull_request_urls = [
393+ "https://api.github.com/repos/user/repo/pulls/1"
394+ ]
395+
396+ # Make pull_request() raise TypeError (simulating ghost user scenario)
397+ mock_issue .issue .pull_request .side_effect = TypeError (
398+ "'NoneType' object is not subscriptable"
399+ )
400+ mock_issue .issue .comments .return_value = []
401+ mock_issue .issue .assignee = None
402+ mock_issue .issue .assignees = None
403+
404+ issues = [mock_issue ]
405+
406+ # Mock the measure functions to avoid additional complexities
407+ with unittest .mock .patch ( # type: ignore
408+ "issue_metrics.measure_time_to_first_response" ,
409+ return_value = timedelta (days = 1 ),
410+ ), unittest .mock .patch ( # type: ignore
411+ "issue_metrics.measure_time_to_close" , return_value = None
412+ ):
413+ # Call the function and verify it doesn't crash
414+ (
415+ result_issues_with_metrics ,
416+ result_num_issues_open ,
417+ result_num_issues_closed ,
418+ ) = get_per_issue_metrics (
419+ issues ,
420+ env_vars = get_env_vars (test = True ),
421+ )
422+
423+ # Verify the function completed successfully despite the TypeError
424+ self .assertEqual (len (result_issues_with_metrics ), 1 )
425+ self .assertEqual (result_num_issues_open , 1 )
426+ self .assertEqual (result_num_issues_closed , 0 )
427+
428+ # Verify the issue was processed with pull_request as None
429+ issue_metric = result_issues_with_metrics [0 ]
430+ self .assertEqual (issue_metric .title , "PR with Ghost User" )
431+ self .assertEqual (issue_metric .author , "existing_user" )
432+
368433
369434class TestDiscussionMetrics (unittest .TestCase ):
370435 """Test suite for the discussion_metrics function."""
0 commit comments