Coverage for tests / unit / logging / test_console_logger.py: 100%

51 statements  

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

1"""Unit tests for console logger output and summaries.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6 

7import pytest 

8from assertpy import assert_that 

9 

10from lintro.enums.action import Action 

11from lintro.utils.console import ThreadSafeConsoleLogger, create_logger 

12 

13 

14def test_create_logger_and_basic_methods( 

15 tmp_path: Path, 

16 capsys: pytest.CaptureFixture[str], 

17) -> None: 

18 """Exercise basic logging methods and ensure files are created. 

19 

20 Args: 

21 tmp_path: Temporary directory for artifacts. 

22 capsys: Pytest capture fixture for stdout. 

23 """ 

24 logger = create_logger(run_dir=tmp_path, verbose=True, raw_output=False) 

25 assert_that(isinstance(logger, ThreadSafeConsoleLogger)).is_true() 

26 logger.info("info message") 

27 logger.debug("debug message") 

28 logger.warning("warn message") 

29 logger.error("error message") 

30 logger.print_lintro_header() 

31 logger.print_tool_header(tool_name="ruff", action="check") 

32 logger.print_tool_result(tool_name="ruff", output="", issues_count=0) 

33 raw = ( 

34 "\n [*] 2 fixable\n" 

35 " Formatting issues:\n" 

36 " Would reformat: file1.py\n" 

37 " Would reformat: file2.py\n" 

38 " Found 3 issue(s) that cannot be auto-fixed\n" 

39 " " 

40 ).strip() 

41 logger.print_tool_result( 

42 tool_name="ruff", 

43 output="some formatted table", 

44 issues_count=3, 

45 raw_output_for_meta=raw, 

46 action=Action.CHECK, 

47 ) 

48 

49 class Result: 

50 def __init__( 

51 self, 

52 name: str, 

53 issues_count: int, 

54 success: bool, 

55 output: str = "", 

56 ) -> None: 

57 self.name = name 

58 self.issues_count = issues_count 

59 self.success = success 

60 self.output = output 

61 

62 logger.print_execution_summary( 

63 action=Action.CHECK, 

64 tool_results=[Result("ruff", 1, False)], 

65 ) 

66 

67 class FmtResult: 

68 def __init__( 

69 self, 

70 name: str, 

71 fixed: int, 

72 remaining: int, 

73 success: bool = True, 

74 output: str = "", 

75 ) -> None: 

76 self.name = name 

77 self.fixed_issues_count = fixed 

78 self.remaining_issues_count = remaining 

79 self.success = success 

80 self.output = output 

81 

82 logger.print_execution_summary( 

83 action=Action.FIX, 

84 tool_results=[FmtResult("ruff", fixed=2, remaining=0, success=True)], 

85 ) 

86 logger.save_console_log() 

87 assert_that((tmp_path / "console.log").exists()).is_true() 

88 out = capsys.readouterr().out 

89 assert_that(out).contains("LINTRO") 

90 assert_that(out).contains("Running ruff (check)") 

91 # Output should contain either issue-related text or pass/fail status 

92 assert_that( 

93 "issues" in out.lower() or "PASS" in out or "FAIL" in out, 

94 ).is_true() 

95 

96 

97def test_summary_marks_fail_on_tool_failure( 

98 tmp_path: Path, 

99 capsys: pytest.CaptureFixture[str], 

100) -> None: 

101 """Ensure summary marks FAIL when any tool result indicates failure. 

102 

103 Args: 

104 tmp_path: Temporary directory for artifacts. 

105 capsys: Pytest capture fixture for stdout. 

106 """ 

107 logger = create_logger(run_dir=tmp_path, verbose=False, raw_output=False) 

108 

109 class Result: 

110 def __init__( 

111 self, 

112 name: str, 

113 issues_count: int, 

114 success: bool, 

115 output: str = "", 

116 ) -> None: 

117 self.name = name 

118 self.issues_count = issues_count 

119 self.success = success 

120 self.output = output 

121 

122 logger.print_execution_summary( 

123 action=Action.CHECK, 

124 tool_results=[Result("bandit", 0, False, output="Failed to parse")], 

125 ) 

126 out = capsys.readouterr().out 

127 assert_that(out).contains("FAIL") 

128 assert_that(out.split("FAIL")[0]).does_not_contain("PASS")