Coverage for tests / unit / cli_utils / command_chainer / test_execute.py: 100%

68 statements  

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

1"""Tests for CommandChainer execute_chain and _execute_single_command methods.""" 

2 

3from __future__ import annotations 

4 

5from unittest.mock import patch 

6 

7import click 

8import pytest 

9from assertpy import assert_that 

10 

11from lintro.cli_utils.command_chainer import CommandChainer 

12 

13 

14def test_execute_chain_all_success(mock_group: click.Group) -> None: 

15 """Test execution of chain where all commands succeed. 

16 

17 Args: 

18 mock_group: Mocked Click group fixture. 

19 """ 

20 chainer = CommandChainer(mock_group) 

21 ctx = click.Context(mock_group) 

22 

23 with patch.object( 

24 chainer, 

25 "_execute_single_command", 

26 return_value=0, 

27 ) as mock_exec: 

28 result = chainer.execute_chain(ctx, [["fmt", "."], ["chk", "."]]) 

29 

30 assert_that(result).is_equal_to(0) 

31 assert_that(mock_exec.call_count).is_equal_to(2) 

32 

33 

34def test_execute_chain_returns_max_exit_code(mock_group: click.Group) -> None: 

35 """Test that execute_chain returns the maximum exit code. 

36 

37 Args: 

38 mock_group: Mocked Click group fixture. 

39 """ 

40 chainer = CommandChainer(mock_group) 

41 ctx = click.Context(mock_group) 

42 

43 with patch.object( 

44 chainer, 

45 "_execute_single_command", 

46 side_effect=[0, 2, 1], 

47 ): 

48 result = chainer.execute_chain( 

49 ctx, 

50 [["fmt", "."], ["chk", "."], ["tst"]], 

51 ) 

52 

53 assert_that(result).is_equal_to(2) 

54 

55 

56def test_execute_chain_empty_groups(mock_group: click.Group) -> None: 

57 """Test execution with empty command groups. 

58 

59 Args: 

60 mock_group: Mocked Click group fixture. 

61 """ 

62 chainer = CommandChainer(mock_group) 

63 ctx = click.Context(mock_group) 

64 

65 result = chainer.execute_chain(ctx, []) 

66 

67 assert_that(result).is_equal_to(0) 

68 

69 

70def test_execute_chain_skips_empty_groups(mock_group: click.Group) -> None: 

71 """Test that empty groups within the list are skipped. 

72 

73 Args: 

74 mock_group: Mocked Click group fixture. 

75 """ 

76 chainer = CommandChainer(mock_group) 

77 ctx = click.Context(mock_group) 

78 

79 with patch.object( 

80 chainer, 

81 "_execute_single_command", 

82 return_value=0, 

83 ) as mock_exec: 

84 result = chainer.execute_chain(ctx, [["fmt"], [], ["chk"]]) 

85 

86 assert_that(result).is_equal_to(0) 

87 assert_that(mock_exec.call_count).is_equal_to(2) 

88 

89 

90def test_execute_single_command_success(mock_group: click.Group) -> None: 

91 """Test successful single command execution. 

92 

93 Args: 

94 mock_group: Mocked Click group fixture. 

95 """ 

96 chainer = CommandChainer(mock_group) 

97 parent_ctx = click.Context(mock_group, info_name="lintro") 

98 

99 result = chainer._execute_single_command(parent_ctx, ["fmt", "."]) 

100 

101 assert_that(result).is_equal_to(0) 

102 

103 

104def test_execute_single_command_handles_system_exit(mock_group: click.Group) -> None: 

105 """Test handling of SystemExit from command. 

106 

107 Args: 

108 mock_group: Mocked Click group fixture. 

109 """ 

110 chainer = CommandChainer(mock_group) 

111 parent_ctx = click.Context(mock_group, info_name="lintro") 

112 

113 with patch.object( 

114 mock_group, 

115 "invoke", 

116 side_effect=SystemExit(2), 

117 ): 

118 result = chainer._execute_single_command(parent_ctx, ["fmt"]) 

119 

120 assert_that(result).is_equal_to(2) 

121 

122 

123def test_execute_single_command_handles_system_exit_none( 

124 mock_group: click.Group, 

125) -> None: 

126 """Test handling of SystemExit with None code. 

127 

128 Args: 

129 mock_group: Mocked Click group fixture. 

130 """ 

131 chainer = CommandChainer(mock_group) 

132 parent_ctx = click.Context(mock_group, info_name="lintro") 

133 

134 with patch.object( 

135 mock_group, 

136 "invoke", 

137 side_effect=SystemExit(None), 

138 ): 

139 result = chainer._execute_single_command(parent_ctx, ["fmt"]) 

140 

141 assert_that(result).is_equal_to(0) 

142 

143 

144def test_execute_single_command_reraises_keyboard_interrupt( 

145 mock_group: click.Group, 

146) -> None: 

147 """Test that KeyboardInterrupt is re-raised. 

148 

149 Args: 

150 mock_group: Mocked Click group fixture. 

151 """ 

152 chainer = CommandChainer(mock_group) 

153 parent_ctx = click.Context(mock_group, info_name="lintro") 

154 

155 with patch.object( 

156 mock_group, 

157 "invoke", 

158 side_effect=KeyboardInterrupt(), 

159 ): 

160 with pytest.raises(KeyboardInterrupt): 

161 chainer._execute_single_command(parent_ctx, ["fmt"]) 

162 

163 

164def test_execute_single_command_handles_exception(mock_group: click.Group) -> None: 

165 """Test handling of generic exceptions. 

166 

167 Args: 

168 mock_group: Mocked Click group fixture. 

169 """ 

170 chainer = CommandChainer(mock_group) 

171 parent_ctx = click.Context(mock_group, info_name="lintro") 

172 

173 with patch.object( 

174 mock_group, 

175 "make_context", 

176 side_effect=RuntimeError("test error"), 

177 ): 

178 result = chainer._execute_single_command(parent_ctx, ["fmt"]) 

179 

180 assert_that(result).is_equal_to(1) 

181 

182 

183def test_execute_single_command_uses_exit_code_attribute( 

184 mock_group: click.Group, 

185) -> None: 

186 """Test that exit_code attribute from exception is used. 

187 

188 Args: 

189 mock_group: Mocked Click group fixture. 

190 """ 

191 chainer = CommandChainer(mock_group) 

192 parent_ctx = click.Context(mock_group, info_name="lintro") 

193 

194 class CustomError(Exception): 

195 """Custom error with exit_code attribute.""" 

196 

197 exit_code = 42 

198 

199 with patch.object( 

200 mock_group, 

201 "make_context", 

202 side_effect=CustomError("custom error"), 

203 ): 

204 result = chainer._execute_single_command(parent_ctx, ["fmt"]) 

205 

206 assert_that(result).is_equal_to(42)