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

32 statements  

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

1"""Tests for output logging in execute_ruff_check.""" 

2 

3from __future__ import annotations 

4 

5from unittest.mock import MagicMock, patch 

6 

7from assertpy import assert_that 

8 

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

10 

11 

12def test_check_failure_logs_output_to_debug_only( 

13 mock_ruff_tool: MagicMock, 

14) -> None: 

15 """Verify check output is logged to debug only, not warning. 

16 

17 When ruff check fails (exit code non-zero due to issues found), 

18 the raw JSON output should only be logged at debug level since 

19 it is already parsed and displayed as a formatted table. 

20 

21 Args: 

22 mock_ruff_tool: Mock RuffTool instance for testing. 

23 """ 

24 # Create output longer than 2000 chars 

25 long_output = "x" * 3000 

26 

27 with ( 

28 patch( 

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

30 return_value=["test.py"], 

31 ), 

32 patch( 

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

34 return_value=(False, long_output), 

35 ), 

36 patch( 

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

38 return_value=[], 

39 ), 

40 patch("lintro.tools.implementations.ruff.check.logger") as mock_logger, 

41 ): 

42 execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

43 

44 # Verify full output was logged to debug 

45 debug_calls = [str(call) for call in mock_logger.debug.call_args_list] 

46 full_output_logged = any("check full output" in call for call in debug_calls) 

47 assert_that(full_output_logged).described_as( 

48 f"Expected full output in debug calls: {debug_calls}", 

49 ).is_true() 

50 

51 # Verify no truncation warning was logged (raw JSON should not appear in console) 

52 warning_calls = [str(call) for call in mock_logger.warning.call_args_list] 

53 truncation_warning = any( 

54 "check failed with output" in call for call in warning_calls 

55 ) 

56 assert_that(truncation_warning).described_as( 

57 f"Did not expect 'check failed with output' warning: {warning_calls}", 

58 ).is_false() 

59 

60 

61def test_format_check_failure_logs_output_to_debug_only( 

62 mock_ruff_tool: MagicMock, 

63) -> None: 

64 """Verify format check output is logged to debug only, not warning. 

65 

66 When ruff format --check fails (exit code non-zero due to formatting issues), 

67 the output should only be logged at debug level since it is already 

68 parsed and displayed as a formatted table. 

69 

70 Args: 

71 mock_ruff_tool: Mock RuffTool instance for testing. 

72 """ 

73 mock_ruff_tool.options["format_check"] = True 

74 

75 # Create output longer than 2000 chars 

76 long_format_output = "Would reformat: " + "x" * 3000 

77 

78 with ( 

79 patch( 

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

81 return_value=["test.py"], 

82 ), 

83 patch( 

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

85 ) as mock_subprocess, 

86 patch( 

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

88 return_value=[], 

89 ), 

90 patch( 

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

92 return_value=[], 

93 ), 

94 patch("lintro.tools.implementations.ruff.check.logger") as mock_logger, 

95 ): 

96 # First call succeeds (lint), second call fails (format) 

97 mock_subprocess.side_effect = [ 

98 (True, "[]"), 

99 (False, long_format_output), 

100 ] 

101 

102 execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

103 

104 # Verify full output was logged to debug 

105 debug_calls = [str(call) for call in mock_logger.debug.call_args_list] 

106 full_output_logged = any( 

107 "format check full output" in call for call in debug_calls 

108 ) 

109 assert_that(full_output_logged).described_as( 

110 f"Expected full output in debug calls: {debug_calls}", 

111 ).is_true() 

112 

113 # Verify no truncation warning was logged 

114 warning_calls = [str(call) for call in mock_logger.warning.call_args_list] 

115 truncation_warning = any( 

116 "format check failed with output" in call for call in warning_calls 

117 ) 

118 assert_that(truncation_warning).described_as( 

119 f"Did not expect 'format check failed with output' warning: {warning_calls}", 

120 ).is_false() 

121 

122 

123def test_check_success_does_not_log_output( 

124 mock_ruff_tool: MagicMock, 

125) -> None: 

126 """Verify successful check does not log output unnecessarily. 

127 

128 When ruff check succeeds (no issues), there should be no output 

129 logged to debug since there's nothing to report. 

130 

131 Args: 

132 mock_ruff_tool: Mock RuffTool instance for testing. 

133 """ 

134 with ( 

135 patch( 

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

137 return_value=["test.py"], 

138 ), 

139 patch( 

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

141 return_value=(True, "[]"), 

142 ), 

143 patch( 

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

145 return_value=[], 

146 ), 

147 patch("lintro.tools.implementations.ruff.check.logger") as mock_logger, 

148 ): 

149 execute_ruff_check(mock_ruff_tool, ["/test/project"]) 

150 

151 # Verify no "check full output" logged when success 

152 debug_calls = [str(call) for call in mock_logger.debug.call_args_list] 

153 full_output_logged = any("check full output" in call for call in debug_calls) 

154 assert_that(full_output_logged).described_as( 

155 f"Did not expect 'check full output' on success: {debug_calls}", 

156 ).is_false()