@@ -33,10 +33,9 @@ class TestModeSession:
3333 is_yellow_friendly : bool
3434 ci_mode : bool
3535 cancel_event : threading .Event = field (default_factory = threading .Event )
36- """Set to ask the in-progress test to stop early so another can run"""
3736
3837
39- class _ResultCollector :
38+ class ResultCollector :
4039 """A pytest plugin that records the pass/fail outcome of a run's tests."""
4140
4241 def __init__ (self , cancel_event ) -> None :
@@ -79,37 +78,9 @@ def summary(self, exit_code) -> str:
7978 return f"{ status } : { passed } /{ total } passed"
8079
8180
82- def _reset_session_state (session : TestModeSession ) -> None :
83- """Halts the AI and clears tactic overrides between runs.
84-
85- Keeps each run hermetic and, for field tests, stops the robots once a test
86- finishes.
87-
88- :param session: the active TestModeSession.
89- """
90- context = session .context
91- try :
92- context .gamecontroller .send_gc_command (
93- gc_command = Command .Type .HALT , team = Team .UNKNOWN
94- )
95- empty_tactics = AssignedTacticPlayControlParams ()
96- context .blue_full_system_proto_unix_io .send_proto (
97- AssignedTacticPlayControlParams , empty_tactics
98- )
99- context .yellow_full_system_proto_unix_io .send_proto (
100- AssignedTacticPlayControlParams , empty_tactics
101- )
102- except Exception as exception :
103- logger .warning (f"Failed to reset state after test: { exception } " )
104-
105-
10681def run_selected_test (session : TestModeSession , test_path : str ) -> str :
10782 """Runs a single gameplay test bound to the given session.
10883
109- Sets fixture.ACTIVE_SESSION so the gameplay_test_runner fixture binds the
110- test to the open Thunderscope, runs the test in-process with pytest, then
111- clears the session and resets state.
112-
11384 :param session: the active TestModeSession.
11485 :param test_path: absolute path to the test file to run.
11586 :return: a human-readable status string describing the outcome.
@@ -118,7 +89,7 @@ def run_selected_test(session: TestModeSession, test_path: str) -> str:
11889 # Clear once per run (not per test in the file) so a cancel set during the
11990 # run stops every remaining test, not just the current one.
12091 session .cancel_event .clear ()
121- collector = _ResultCollector (session .cancel_event )
92+ collector = ResultCollector (session .cancel_event )
12293 try :
12394 # Pass the fixture module as a plugin so gameplay_test_runner is available
12495 # regardless of where pytest resolves conftest.py for the source-tree test.
@@ -135,7 +106,6 @@ def run_selected_test(session: TestModeSession, test_path: str) -> str:
135106 )
136107 finally :
137108 fixture .ACTIVE_SESSION = None
138- _reset_session_state (session )
139109 return collector .summary (exit_code )
140110
141111
@@ -172,10 +142,6 @@ def _build_test_args(main_args) -> argparse.Namespace:
172142def launch_test_mode (main_args ) -> None :
173143 """Launches Thunderscope in test mode and runs the Qt event loop.
174144
175- Starts the gameplay-test binaries once, builds a Thunderscope view with the
176- Test Runner widget, and keeps everything alive so that tests selected in the
177- widget run against the already-open Thunderscope.
178-
179145 :param main_args: parsed thunderscope_main command-line arguments.
180146 """
181147 args = _build_test_args (main_args )
@@ -188,22 +154,16 @@ def launch_test_mode(main_args) -> None:
188154 )
189155
190156 with session_cm as context :
191- # Must construct the QApplication before any QWidget (the Test Runner
192- # widget) is created. configure_*_view calls this again, but it is
193- # idempotent.
157+ # Must construct the QApplication before any QWidget
194158 initialize_application ()
195159
196- # Holds the session so the run callback can reach it; the session is only
197- # created after the Thunderscope (which needs the widget) exists.
198- session_holder = {}
160+ session = None
199161
200162 def run_callback (test_path : str ) -> str :
201- return run_selected_test (session_holder [ " session" ] , test_path )
163+ return run_selected_test (session , test_path )
202164
203165 def cancel_callback () -> None :
204- session = session_holder .get ("session" )
205- if session is not None :
206- session .cancel_event .set ()
166+ session .cancel_event .set ()
207167
208168 test_runner_widget = TScopeWidget (
209169 name = "Test Runner" ,
@@ -225,7 +185,7 @@ def cancel_callback() -> None:
225185 context , main_args .layout , extra_widgets = [test_runner_widget ]
226186 )
227187
228- session_holder [ " session" ] = TestModeSession (
188+ session = TestModeSession (
229189 context = context ,
230190 thunderscope = thunderscope ,
231191 run_field_test = args .run_field_test ,
0 commit comments