Coverage for tests / unit / tools / ruff / check / test_json_parsing.py: 100%

35 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Tests for JSON output parsing in execute_ruff_check.""" 

2 

3from __future__ import annotations 

4 

5from typing import cast 

6from unittest.mock import MagicMock, patch 

7 

8from assertpy import assert_that 

9 

10from lintro.parsers.ruff.ruff_issue import RuffIssue 

11from lintro.tools.implementations.ruff.check import execute_ruff_check 

12 

13 

14def test_execute_ruff_check_parses_json_output_correctly( 

15 mock_ruff_tool: MagicMock, 

16 sample_ruff_json_output: str, 

17) -> None: 

18 """Parse JSON output and create correct issue objects. 

19 

20 Args: 

21 mock_ruff_tool: Mock RuffTool instance for testing. 

22 sample_ruff_json_output: Sample JSON output from ruff. 

23 """ 

24 from lintro.parsers.ruff.ruff_parser import parse_ruff_output 

25 

26 with ( 

27 patch( 

28 "lintro.tools.implementations.ruff.check.walk_files_with_excludes", 

29 return_value=["test.py"], 

30 ), 

31 patch( 

32 "lintro.tools.implementations.ruff.check.run_subprocess_with_timeout", 

33 return_value=(False, sample_ruff_json_output), 

34 ), 

35 patch( 

36 "lintro.tools.implementations.ruff.check.parse_ruff_output", 

37 side_effect=parse_ruff_output, 

38 ), 

39 ): 

40 result = execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

41 

42 # Verify overall result reflects subprocess failure and issues found 

43 assert_that(result.success).is_false() 

44 assert_that(result.issues_count).is_equal_to(2) 

45 assert_that(result.issues).is_not_none() 

46 assert_that(result.issues).is_length(2) 

47 

48 # Verify first issue 

49 first_issue = cast(RuffIssue, result.issues[0]) # type: ignore[index] # validated via is_not_none 

50 assert_that(first_issue.code).is_equal_to("F401") 

51 assert_that(first_issue.file).is_equal_to("test.py") 

52 assert_that(first_issue.line).is_equal_to(1) 

53 assert_that(first_issue.column).is_equal_to(1) 

54 

55 # Verify second issue 

56 second_issue = cast(RuffIssue, result.issues[1]) # type: ignore[index] # validated via is_not_none 

57 assert_that(second_issue.code).is_equal_to("E501") 

58 

59 

60def test_execute_ruff_check_empty_json_output( 

61 mock_ruff_tool: MagicMock, 

62 sample_ruff_json_empty_output: str, 

63) -> None: 

64 """Handle empty JSON output correctly. 

65 

66 Args: 

67 mock_ruff_tool: Mock RuffTool instance for testing. 

68 sample_ruff_json_empty_output: Sample empty JSON output from ruff. 

69 """ 

70 with ( 

71 patch( 

72 "lintro.tools.implementations.ruff.check.walk_files_with_excludes", 

73 return_value=["test.py"], 

74 ), 

75 patch( 

76 "lintro.tools.implementations.ruff.check.run_subprocess_with_timeout", 

77 return_value=(True, sample_ruff_json_empty_output), 

78 ), 

79 patch( 

80 "lintro.tools.implementations.ruff.check.parse_ruff_output", 

81 return_value=[], 

82 ), 

83 ): 

84 result = execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

85 

86 assert_that(result.success).is_true() 

87 assert_that(result.issues_count).is_equal_to(0) 

88 

89 

90def test_execute_ruff_check_parses_format_check_output( 

91 mock_ruff_tool: MagicMock, 

92 sample_ruff_format_check_output: str, 

93) -> None: 

94 """Parse format check output and create correct format issues. 

95 

96 Args: 

97 mock_ruff_tool: Mock RuffTool instance for testing. 

98 sample_ruff_format_check_output: Sample format check output from ruff. 

99 """ 

100 mock_ruff_tool.options["format_check"] = True 

101 

102 from lintro.parsers.ruff.ruff_parser import parse_ruff_format_check_output 

103 

104 with ( 

105 patch( 

106 "lintro.tools.implementations.ruff.check.walk_files_with_excludes", 

107 return_value=["test.py", "src/module.py"], 

108 ), 

109 patch( 

110 "lintro.tools.implementations.ruff.check.run_subprocess_with_timeout", 

111 return_value=(True, ""), 

112 ), 

113 patch( 

114 "lintro.tools.implementations.ruff.check.parse_ruff_output", 

115 return_value=[], 

116 ), 

117 patch( 

118 "lintro.tools.implementations.ruff.check.parse_ruff_format_check_output", 

119 side_effect=parse_ruff_format_check_output, 

120 ), 

121 ): 

122 # Need a separate mock for the format check subprocess call 

123 with patch( 

124 "lintro.tools.implementations.ruff.check.run_subprocess_with_timeout", 

125 ) as mock_subprocess: 

126 # First call: lint check, Second call: format check 

127 mock_subprocess.side_effect = [ 

128 (True, "[]"), 

129 (False, sample_ruff_format_check_output), 

130 ] 

131 

132 result = execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

133 

134 # Format check subprocess failed, so overall result should be failure 

135 assert_that(result.success).is_false() 

136 assert_that(result.issues_count).is_equal_to(2)