@@ -82,101 +82,87 @@ def test_plain_word_not_semantic(self):
8282 assert is_semantic_pattern ("config" ) is False
8383
8484
85+ def _run_with_input (tool_name : str , tool_input : dict | None = None ) -> int :
86+ """Simulate hook invocation with the given tool name and optional input."""
87+ hook_data = {"tool_name" : tool_name }
88+ if tool_input is not None :
89+ hook_data ["tool_input" ] = tool_input
90+ stdin = StringIO (json .dumps (hook_data ))
91+ with patch ("sys.stdin" , stdin ):
92+ return run_tool_redirect ()
93+
94+
8595class TestBlockedTools :
8696 """Tests for tools that should be blocked (exit code 2)."""
8797
88- def _run_with_input (self , tool_name : str , tool_input : dict | None = None ) -> int :
89- hook_data = {"tool_name" : tool_name }
90- if tool_input is not None :
91- hook_data ["tool_input" ] = tool_input
92- stdin = StringIO (json .dumps (hook_data ))
93- with patch ("sys.stdin" , stdin ):
94- return run_tool_redirect ()
95-
9698 def test_blocks_web_search (self ):
97- result = self . _run_with_input ("WebSearch" , {"query" : "python tutorial" })
99+ result = _run_with_input ("WebSearch" , {"query" : "python tutorial" })
98100 assert result == 2
99101
100102 def test_blocks_web_fetch (self ):
101- result = self . _run_with_input ("WebFetch" , {"url" : "https://example.com" })
103+ result = _run_with_input ("WebFetch" , {"url" : "https://example.com" })
102104 assert result == 2
103105
104106 def test_blocks_enter_plan_mode (self ):
105- result = self . _run_with_input ("EnterPlanMode" )
107+ result = _run_with_input ("EnterPlanMode" )
106108 assert result == 2
107109
108110 def test_blocks_exit_plan_mode (self ):
109- result = self . _run_with_input ("ExitPlanMode" )
111+ result = _run_with_input ("ExitPlanMode" )
110112 assert result == 2
111113
112114
113115class TestHintedTools :
114116 """Tests for tools that get hints but are allowed (exit code 0)."""
115117
116- def _run_with_input (self , tool_name : str , tool_input : dict | None = None ) -> int :
117- hook_data = {"tool_name" : tool_name }
118- if tool_input is not None :
119- hook_data ["tool_input" ] = tool_input
120- stdin = StringIO (json .dumps (hook_data ))
121- with patch ("sys.stdin" , stdin ):
122- return run_tool_redirect ()
123-
124118 def test_hints_grep_with_semantic_pattern (self ):
125- result = self . _run_with_input ("Grep" , {"pattern" : "where is config loaded" })
119+ result = _run_with_input ("Grep" , {"pattern" : "where is config loaded" })
126120 assert result == 0
127121
128122 def test_no_hint_grep_with_code_pattern (self ):
129- result = self . _run_with_input ("Grep" , {"pattern" : "def save_config" })
123+ result = _run_with_input ("Grep" , {"pattern" : "def save_config" })
130124 assert result == 0
131125
132126 def test_hints_task_explore (self ):
133- result = self . _run_with_input ("Task" , {"subagent_type" : "Explore" })
127+ result = _run_with_input ("Task" , {"subagent_type" : "Explore" })
134128 assert result == 0
135129
136130 def test_hints_task_generic_subagent (self ):
137131 """Non-allowed subagent types get a hint."""
138- result = self . _run_with_input ("Task" , {"subagent_type" : "general-purpose" })
132+ result = _run_with_input ("Task" , {"subagent_type" : "general-purpose" })
139133 assert result == 0
140134
141135 def test_no_hint_task_spec_reviewer (self ):
142136 """Spec reviewer sub-agents should be allowed without hints."""
143- result = self . _run_with_input ("Task" , {"subagent_type" : "pilot:spec-reviewer-compliance" })
137+ result = _run_with_input ("Task" , {"subagent_type" : "pilot:spec-reviewer-compliance" })
144138 assert result == 0
145139
146140 def test_no_hint_task_plan_verifier (self ):
147- result = self . _run_with_input ("Task" , {"subagent_type" : "pilot:plan-verifier" })
141+ result = _run_with_input ("Task" , {"subagent_type" : "pilot:plan-verifier" })
148142 assert result == 0
149143
150144 def test_no_hint_task_plan_challenger (self ):
151- result = self . _run_with_input ("Task" , {"subagent_type" : "pilot:plan-challenger" })
145+ result = _run_with_input ("Task" , {"subagent_type" : "pilot:plan-challenger" })
152146 assert result == 0
153147
154148
155149class TestAllowedTools :
156150 """Tests for tools that should pass through without blocks or hints."""
157151
158- def _run_with_input (self , tool_name : str , tool_input : dict | None = None ) -> int :
159- hook_data = {"tool_name" : tool_name }
160- if tool_input is not None :
161- hook_data ["tool_input" ] = tool_input
162- stdin = StringIO (json .dumps (hook_data ))
163- with patch ("sys.stdin" , stdin ):
164- return run_tool_redirect ()
165-
166152 def test_allows_read (self ):
167- assert self . _run_with_input ("Read" , {"file_path" : "/foo.py" }) == 0
153+ assert _run_with_input ("Read" , {"file_path" : "/foo.py" }) == 0
168154
169155 def test_allows_write (self ):
170- assert self . _run_with_input ("Write" , {"file_path" : "/foo.py" }) == 0
156+ assert _run_with_input ("Write" , {"file_path" : "/foo.py" }) == 0
171157
172158 def test_allows_edit (self ):
173- assert self . _run_with_input ("Edit" , {"file_path" : "/foo.py" }) == 0
159+ assert _run_with_input ("Edit" , {"file_path" : "/foo.py" }) == 0
174160
175161 def test_allows_bash (self ):
176- assert self . _run_with_input ("Bash" , {"command" : "ls" }) == 0
162+ assert _run_with_input ("Bash" , {"command" : "ls" }) == 0
177163
178164 def test_allows_task_create (self ):
179- assert self . _run_with_input ("TaskCreate" , {"subject" : "test" }) == 0
165+ assert _run_with_input ("TaskCreate" , {"subject" : "test" }) == 0
180166
181167
182168class TestEdgeCases :
0 commit comments