@@ -578,11 +578,13 @@ async def passthrough_awaitable(awaitable):
578578 # Verify the hub was created and used correctly
579579 mock_hub_class .assert_called_once_with ("mock_device" )
580580 mock_hub .connect .assert_called_once ()
581+
581582 assert mock_hub .run .call_count == 2
582583 mock_hub .run .assert_called_with (temp_path , wait = True )
583584 mock_hub .download .assert_called_once_with (temp_path )
584585 mock_hub .start_user_program .assert_called_once ()
585586 mock_hub ._wait_for_user_program_stop .assert_called_once ()
587+
586588 assert mock_selector .call_count == 4
587589 mock_hub .disconnect .assert_called_once ()
588590
@@ -779,6 +781,59 @@ async def mock_menu_function():
779781 # this should only be called once because the menu was canceled the first two times it was called
780782 mock_hub .run .assert_called_once_with (temp_path , wait = True )
781783
784+ @pytest .mark .asyncio
785+ async def test_stay_connected_menu_run_stored (self ):
786+ """Test that the run_stored program option doesn't call an inaccessible method on an old hub."""
787+
788+ async def passthrough_awaitable (awaitable ):
789+ return await awaitable
790+
791+ # Create a mock hub
792+ old_mock_hub = AsyncMock ()
793+
794+ # simulate an old hub that can't handle the run_stored_program option
795+ old_mock_hub .fw_version = Version ("3.2.0-beta.3" )
796+ old_mock_hub .run = AsyncMock ()
797+ old_mock_hub .connect = AsyncMock ()
798+ old_mock_hub .start_user_program = AsyncMock ()
799+ old_mock_hub .race_disconnect = old_mock_hub .race_power_button_press = AsyncMock (
800+ side_effect = passthrough_awaitable
801+ )
802+
803+ # create a mock questionary menu
804+ mock_selector = AsyncMock ()
805+ mock_selector .ask_async .side_effect = [
806+ "Run Stored Program" ,
807+ "Exit" ,
808+ ]
809+
810+ # Set up mocks using ExitStack
811+ with contextlib .ExitStack () as stack :
812+ # Create and manage temporary file
813+
814+ # Create args
815+ args = argparse .Namespace (
816+ conntype = "ble" ,
817+ file = stack .enter_context (
818+ tempfile .NamedTemporaryFile (
819+ suffix = ".py" , mode = "w+" , delete = False , encoding = "utf-8"
820+ )
821+ ),
822+ name = "MyHub" ,
823+ start = True ,
824+ wait = True ,
825+ stay_connected = True ,
826+ )
827+
828+ stack .enter_context (patch ("questionary.select" , return_value = mock_selector ))
829+
830+ # Run the command
831+ run_cmd = Run ()
832+ await run_cmd .stay_connected_menu (old_mock_hub , args )
833+
834+ old_mock_hub .start_user_program .assert_not_called ()
835+ old_mock_hub ._wait_for_user_program_stop .assert_not_called ()
836+
782837
783838class TestCompile :
784839 """Tests for the Compile command."""
0 commit comments