Coverage for tests / unit / tools / manager / test_tool_manager.py: 100%

74 statements  

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

1"""Unit tests for ToolManager using the plugin registry system.""" 

2 

3from __future__ import annotations 

4 

5import pytest 

6from assertpy import assert_that 

7 

8from lintro.enums.tool_name import ToolName 

9from lintro.tools.core.tool_manager import ToolManager 

10from tests.constants import MIN_EXPECTED_TOOLS 

11 

12 

13def test_tool_manager_get_all_tools() -> None: 

14 """Verify ToolManager discovers and returns all registered tools.""" 

15 tm = ToolManager() 

16 available = tm.get_all_tools() 

17 

18 # Should have all expected tools discovered 

19 assert_that(len(available)).is_greater_than_or_equal_to(MIN_EXPECTED_TOOLS) 

20 

21 # Verify ruff is available 

22 assert_that(available).contains_key(ToolName.RUFF) 

23 ruff_tool = available[ToolName.RUFF] 

24 assert_that(ruff_tool.definition.name).is_equal_to(ToolName.RUFF) 

25 

26 

27def test_tool_manager_get_tool_by_name() -> None: 

28 """Verify get_tool returns correct tool by name.""" 

29 tm = ToolManager() 

30 

31 ruff_tool = tm.get_tool(ToolName.RUFF) 

32 assert_that(ruff_tool.definition.name).is_equal_to(ToolName.RUFF) 

33 

34 hadolint_tool = tm.get_tool(ToolName.HADOLINT) 

35 assert_that(hadolint_tool.definition.name).is_equal_to(ToolName.HADOLINT) 

36 

37 

38def test_tool_manager_get_tool_case_insensitive() -> None: 

39 """Verify get_tool is case-insensitive.""" 

40 tm = ToolManager() 

41 

42 # Test with ToolName enum 

43 ruff_enum = tm.get_tool(ToolName.RUFF) 

44 # Test with string variations 

45 ruff_upper = tm.get_tool("RUFF") 

46 ruff_mixed = tm.get_tool("Ruff") 

47 

48 assert_that(ruff_enum.definition.name).is_equal_to(ToolName.RUFF) 

49 assert_that(ruff_upper.definition.name).is_equal_to(ToolName.RUFF) 

50 assert_that(ruff_mixed.definition.name).is_equal_to(ToolName.RUFF) 

51 

52 

53def test_tool_manager_get_tool_missing() -> None: 

54 """Raise ValueError when attempting to get an unknown tool.""" 

55 tm = ToolManager() 

56 with pytest.raises(ValueError, match="Unknown tool"): 

57 tm.get_tool("nonexistent-tool-that-does-not-exist") 

58 

59 

60def test_tool_manager_get_check_and_fix_tools() -> None: 

61 """Verify get_check_tools and get_fix_tools return correct subsets.""" 

62 tm = ToolManager() 

63 

64 check_tools = tm.get_check_tools() 

65 fix_tools = tm.get_fix_tools() 

66 

67 # All fix tools should also be check tools 

68 for tool_name in fix_tools: 

69 assert_that(check_tools).contains_key(tool_name) 

70 

71 # Ruff should be in both (can_fix=True) 

72 assert_that(check_tools).contains_key(ToolName.RUFF) 

73 assert_that(fix_tools).contains_key(ToolName.RUFF) 

74 

75 # Hadolint should only be in check tools (can_fix=False) 

76 assert_that(check_tools).contains_key(ToolName.HADOLINT) 

77 assert_that(fix_tools).does_not_contain_key(ToolName.HADOLINT) 

78 

79 

80def test_tool_manager_get_tool_execution_order() -> None: 

81 """Verify tool execution order respects configuration.""" 

82 tm = ToolManager() 

83 

84 # Get execution order for ruff and hadolint 

85 order = tm.get_tool_execution_order([ToolName.RUFF, ToolName.HADOLINT]) 

86 

87 # Both should be in the result (no conflicts) 

88 assert_that(len(order)).is_equal_to(2) 

89 assert_that(order).contains(ToolName.RUFF) 

90 assert_that(order).contains(ToolName.HADOLINT) 

91 

92 

93def test_tool_manager_get_tool_execution_order_with_conflicts() -> None: 

94 """Verify conflict resolution in execution order.""" 

95 tm = ToolManager() 

96 

97 # Verify tools exist before testing conflict resolution 

98 assert tm.get_tool(ToolName.RUFF) is not None 

99 assert tm.get_tool(ToolName.BLACK) is not None 

100 

101 try: 

102 # Temporarily modify conflicts (note: ToolDefinition is frozen, so we need 

103 # to work around this for testing - in practice, conflicts are set at 

104 # registration time) 

105 

106 # Since ToolDefinition is frozen, we can't modify conflicts_with directly 

107 # This test verifies the conflict resolution logic works with the 

108 # existing tool configurations 

109 order = tm.get_tool_execution_order([ToolName.RUFF, ToolName.BLACK]) 

110 

111 # Both should be returned since they don't have conflicts defined 

112 assert_that(len(order)).is_equal_to(2) 

113 

114 # With ignore_conflicts=True, all tools should be returned 

115 order_all = tm.get_tool_execution_order( 

116 [ToolName.RUFF, ToolName.BLACK], 

117 ignore_conflicts=True, 

118 ) 

119 assert_that(len(order_all)).is_equal_to(2) 

120 finally: 

121 # No cleanup needed since we didn't actually modify anything 

122 pass 

123 

124 

125def test_tool_manager_get_tool_names() -> None: 

126 """Verify get_tool_names returns all registered tool names.""" 

127 tm = ToolManager() 

128 names = tm.get_tool_names() 

129 

130 # Should have all expected tools 

131 assert_that(len(names)).is_greater_than_or_equal_to(MIN_EXPECTED_TOOLS) 

132 assert_that(names).contains(ToolName.RUFF) 

133 assert_that(names).contains(ToolName.HADOLINT) 

134 assert_that(names).contains(ToolName.PYTEST) 

135 

136 

137def test_tool_manager_is_tool_registered() -> None: 

138 """Verify is_tool_registered returns correct values.""" 

139 tm = ToolManager() 

140 

141 assert_that(tm.is_tool_registered(ToolName.RUFF)).is_true() 

142 assert_that(tm.is_tool_registered("RUFF")).is_true() # Case insensitive 

143 assert_that(tm.is_tool_registered("nonexistent")).is_false() 

144 

145 

146def test_tool_manager_set_tool_options() -> None: 

147 """Verify set_tool_options correctly configures tools.""" 

148 tm = ToolManager() 

149 

150 # Set options on ruff 

151 tm.set_tool_options(ToolName.RUFF, timeout=60) 

152 

153 # Get the tool and verify options were set 

154 ruff_tool = tm.get_tool(ToolName.RUFF) 

155 assert_that(ruff_tool.options.get("timeout")).is_equal_to(60)