Coverage for tests / unit / utils / async_tool_executor / test_run_tool_async.py: 100%

46 statements  

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

1"""Tests for AsyncToolExecutor.run_tool_async method.""" 

2 

3from __future__ import annotations 

4 

5import asyncio 

6from typing import Any, cast 

7 

8from assertpy import assert_that 

9 

10from lintro.enums.action import Action 

11from lintro.models.core.tool_result import ToolResult 

12from lintro.plugins.base import BaseToolPlugin 

13from lintro.utils.async_tool_executor import AsyncToolExecutor 

14 

15from .conftest import MockToolDefinition, MockToolPlugin 

16 

17 

18def test_run_tool_async_check_success(executor: AsyncToolExecutor) -> None: 

19 """Test successful async execution of check action. 

20 

21 Args: 

22 executor: AsyncToolExecutor fixture. 

23 """ 

24 tool = MockToolPlugin( 

25 definition=MockToolDefinition(name="test_tool"), 

26 ) 

27 

28 async def run_test() -> Any: 

29 # MockToolPlugin implements the same interface as BaseToolPlugin for testing 

30 return await executor.run_tool_async( 

31 cast(BaseToolPlugin, tool), 

32 paths=["."], 

33 action=Action.CHECK, 

34 ) 

35 

36 result = asyncio.run(run_test()) 

37 

38 assert_that(result.success).is_true() 

39 assert_that(result.name).is_equal_to("test_tool") 

40 assert_that(tool.check_called).is_true() 

41 assert_that(tool.fix_called).is_false() 

42 

43 

44def test_run_tool_async_fix_success(executor: AsyncToolExecutor) -> None: 

45 """Test successful async execution of fix action. 

46 

47 Args: 

48 executor: AsyncToolExecutor fixture. 

49 """ 

50 tool = MockToolPlugin( 

51 definition=MockToolDefinition(name="fix_tool"), 

52 ) 

53 

54 async def run_test() -> Any: 

55 # MockToolPlugin implements the same interface as BaseToolPlugin for testing 

56 return await executor.run_tool_async( 

57 cast(BaseToolPlugin, tool), 

58 paths=["."], 

59 action=Action.FIX, 

60 ) 

61 

62 result = asyncio.run(run_test()) 

63 

64 assert_that(result.success).is_true() 

65 assert_that(tool.fix_called).is_true() 

66 assert_that(tool.check_called).is_false() 

67 

68 

69def test_run_tool_async_with_options(executor: AsyncToolExecutor) -> None: 

70 """Test async execution passes options correctly. 

71 

72 Args: 

73 executor: AsyncToolExecutor fixture. 

74 """ 

75 received_options: dict[str, Any] = {} 

76 

77 def check_with_capture( 

78 paths: list[str], 

79 options: dict[str, Any] | None = None, 

80 ) -> ToolResult: 

81 nonlocal received_options 

82 received_options = options or {} 

83 return ToolResult( 

84 name="capture_tool", 

85 success=True, 

86 output="", 

87 issues_count=0, 

88 ) 

89 

90 tool = MockToolPlugin(definition=MockToolDefinition(name="capture_tool")) 

91 # Use object.__setattr__ to bypass dataclass method assignment restriction 

92 object.__setattr__(tool, "check", check_with_capture) 

93 

94 async def run_test() -> Any: 

95 # MockToolPlugin implements the same interface as BaseToolPlugin for testing 

96 return await executor.run_tool_async( 

97 cast(BaseToolPlugin, tool), 

98 paths=["."], 

99 action=Action.CHECK, 

100 options={"verbose": True, "fix": False}, 

101 ) 

102 

103 asyncio.run(run_test()) 

104 

105 assert_that(received_options).contains_key("verbose") 

106 assert_that(received_options["verbose"]).is_true() 

107 

108 

109def test_run_tool_async_with_failure(executor: AsyncToolExecutor) -> None: 

110 """Test async execution handles tool failure. 

111 

112 Args: 

113 executor: AsyncToolExecutor fixture. 

114 """ 

115 failed_result = ToolResult( 

116 name="failing_tool", 

117 success=False, 

118 output="Error occurred", 

119 issues_count=5, 

120 ) 

121 tool = MockToolPlugin( 

122 definition=MockToolDefinition(name="failing_tool"), 

123 check_result=failed_result, 

124 ) 

125 

126 async def run_test() -> Any: 

127 # MockToolPlugin implements the same interface as BaseToolPlugin for testing 

128 return await executor.run_tool_async( 

129 cast(BaseToolPlugin, tool), 

130 paths=["."], 

131 action=Action.CHECK, 

132 ) 

133 

134 result = asyncio.run(run_test()) 

135 

136 assert_that(result.success).is_false() 

137 assert_that(result.issues_count).is_equal_to(5)