def test_force_flash_no_serial_connection(): """ If Mu cannot establish a serial connection to the micro:bit, BUT the path to the micro:bit on the filesystem is known, then fall back to old-school flashing of hex with script appended to the end. """ mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.contrib.uflash.find_microbit", return_value="/bar/microbit"), mock.patch( "mu.contrib.microfs.get_serial"), mock.patch( "mu.contrib.microfs.version", side_effect=IOError("bang")), mock.patch( "mu.logic.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = None mm = MicrobitMode(editor, view) mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() mm.flash_start.assert_called_once_with(b"foo", "/bar/microbit", None, serial_fs=False) mock_flasher_class.assert_called_once_with(["/bar/microbit"], b"foo", None) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished)
def test_flash_force_with_attached_device(microbit): """ Ensure the expected calls are made to DeviceFlasher and a helpful status message is enacted. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": "1.0", "version": ("micro:bit v0.0.9-b'e10a5ff' on 2018-6-8; MicroPython " "v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="/foo/microbit/"), mock.patch( "mu.modes.microbit.microfs.version", return_value=version_info), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "/foo/bar.hex" editor.current_device = microbit mm = MicrobitMode(editor, view) mm.set_buttons = mock.MagicMock() mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() assert mm.flash_thread == mock_flasher assert editor.show_status_message.call_count == 1 mm.set_buttons.assert_called_once_with(flash=False, repl=False, files=False, plotter=False) mm.flash_start.assert_called_once_with(b"foo", "/foo/microbit/", "/foo/bar.hex") mock_flasher_class.assert_called_once_with(["/foo/microbit/"], None, "/foo/bar.hex") mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished) mock_flasher.on_flash_fail.connect.assert_called_once_with( mm.flash_failed) mock_flasher.start.assert_called_once_with()
def test_flash_device_has_latest_firmware_encounters_serial_problem( microbit, ): """ If copy_main encounters an IOError (likely on Windows), revert to old-school flashing. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": uflash.MICROPYTHON_VERSION, "version": ("micro:bit v0.1.0-b'e10a5ff' on 2018-6-8; MicroPython " "v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="bar"), mock.patch( "mu.modes.microbit.microfs.version", return_value=version_info), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = microbit mm = MicrobitMode(editor, view) mm.flash_failed = mock.MagicMock() error = IOError("bang") mm.copy_main = mock.MagicMock(side_effect=error) mm.set_buttons = mock.MagicMock() mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() mm.copy_main.assert_called_once_with(b"foo") mm.flash_start.assert_called_once_with(b"foo", "bar", None, serial_fs=False) mock_flasher_class.assert_called_once_with(["bar"], b"foo", None) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished) mock_flasher.on_flash_fail.connect.assert_called_once_with( mm.flash_failed) mock_flasher.start.assert_called_once_with()
def test_force_flash_user_specified_device_path(): """ Ensure that if a micro:bit is not automatically found by uflash then it prompts the user to locate the device and, assuming a path was given, saves the hex in the expected location. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": uflash.MICROPYTHON_VERSION, "version": ("micro:bit v0.1.0-b'e10a5ff' on 2018-6-8; MicroPython " "v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.contrib.uflash.find_microbit", return_value=None), mock.patch( "mu.contrib.microfs.get_serial"), mock.patch( "mu.contrib.microfs.version", return_value=version_info), mock.patch( "mu.logic.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.get_microbit_path = mock.MagicMock(return_value="/bar/microbit") view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = None mm = MicrobitMode(editor, view) mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() home = HOME_DIRECTORY view.get_microbit_path.assert_called_once_with(home) mm.flash_start.assert_called_once_with(b"foo", "/bar/microbit", None, serial_fs=False) mock_flasher_class.assert_called_once_with(["/bar/microbit"], b"foo", None) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished)
def test_flash_with_attached_device_has_old_firmware(microbit): """ If the device has some unknown old firmware, force flash it. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": "1.0", "version": ("v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="/foo/bar"), mock.patch( "mu.modes.microbit.microfs.version", return_value=version_info), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = microbit mm = MicrobitMode(editor, view) mm.copy_main = mock.MagicMock() mm.set_buttons = mock.MagicMock() mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() assert mm.flash_thread == mock_flasher assert editor.show_status_message.call_count == 1 mm.set_buttons.assert_called_once_with(flash=False, repl=False, files=False, plotter=False) mm.flash_start.assert_called_once_with(b"foo", "/foo/bar", None) mock_flasher_class.assert_called_once_with(["/foo/bar"], None, None) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished) mock_flasher.on_flash_fail.connect.assert_called_once_with( mm.flash_failed) mock_flasher.start.assert_called_once_with()
def test_force_flash_empty_script(microbit_v1_5): """ If the script to be flashed onto the device is empty, this is a signal to force a full flash of the "vanilla" / empty MicroPython runtime onto the device. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": uflash.MICROPYTHON_VERSION, "version": ("micro:bit v0.1.0-b'e10a5ff' on 2018-6-8; MicroPython " "v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.contrib.uflash.find_microbit", return_value="/bar/microbit"), mock.patch( "mu.contrib.microfs.get_serial"), mock.patch( "mu.contrib.microfs.version", return_value=version_info), mock.patch( "mu.logic.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value=" ") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = microbit_v1_5 mm = MicrobitMode(editor, view) mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() mm.flash_start.assert_called_once_with(b" ", "/bar/microbit", None) mock_flasher_class.assert_called_once_with(["/bar/microbit"], None, None) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished)
def test_flash_with_attached_device_and_custom_runtime(microbit_v1_5): """ Ensure the custom runtime is passed into the DeviceFlasher thread. """ mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.base.BaseMode.workspace_dir", return_value=TEST_ROOT), mock.patch( "mu.modes.microbit.uflash.find_microbit", return_value="/foo/microbit/"), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = True editor.current_device = microbit_v1_5 editor.microbit_runtime = os.path.join("tests", "customhextest.hex") mm = MicrobitMode(editor, view) mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() assert editor.show_status_message.call_count == 1 assert (os.path.join("tests", "customhextest.hex") in editor.show_status_message.call_args[0][0]) assert mock_flasher_class.call_count == 1 mm.flash_start.assert_called_once_with( b"foo", "/foo/microbit/", os.path.join("tests", "customhextest.hex"), ) mock_flasher_class.assert_called_once_with( ["/foo/microbit/"], None, os.path.join("tests", "customhextest.hex"), ) mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished) mock_flasher.on_flash_fail.connect.assert_called_once_with( mm.flash_failed) mock_flasher.start.assert_called_once_with()
def test_flash_with_attached_known_device_and_forced(microbit_v1_5): """ If the runtime must be flashed, and the serial number for the device is supported, then flash the built-in MicroPython runtime. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": "1.0.0", "version": ("micro:bit v0.0.9-b'e10a5ff' on 2018-6-8; MicroPython " "v1.9.2-34-gd64154c73 on 2017-09-01"), "machine": "micro:bit with nRF51822", } mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="/bar/microbit"), mock.patch( "mu.modes.microbit.microfs.version", return_value=version_info), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() # Trigger force flash with an empty file. view.current_tab.text = mock.MagicMock(return_value="") editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = microbit_v1_5 mm = MicrobitMode(editor, view) mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() assert mock_flasher_class.call_count == 1 mm.flash_start.assert_called_once_with(b"", "/bar/microbit", None) mock_flasher_class.assert_called_once_with(["/bar/microbit"], None, None)
def test_flash_force_with_no_micropython(microbit): """ Ensure the expected calls are made to DeviceFlasher and a helpful status message is enacted if there is no MicroPython firmware on the device. """ mock_flasher = mock.MagicMock() mock_flasher_class = mock.MagicMock(return_value=mock_flasher) with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="bar"), mock.patch( "mu.modes.microbit.microfs.version", side_effect=ValueError("bang")), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True), mock.patch( "mu.modes.microbit.DeviceFlasher", mock_flasher_class): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "/foo/bar" editor.current_device = microbit mm = MicrobitMode(editor, view) mm.set_buttons = mock.MagicMock() mm.flash_start = mock.MagicMock(side_effect=mm.flash_start) mm.flash() assert mm.flash_thread == mock_flasher assert editor.show_status_message.call_count == 1 mm.set_buttons.assert_called_once_with(flash=False, repl=False, files=False, plotter=False) mm.flash_start.assert_called_once_with(b"foo", "bar", "/foo/bar") mock_flasher_class.assert_called_once_with(["bar"], None, "/foo/bar") mock_flasher.finished.connect.assert_called_once_with( mm.flash_finished) mock_flasher.on_flash_fail.connect.assert_called_once_with( mm.flash_failed) mock_flasher.start.assert_called_once_with()
def test_flash_with_attached_device_has_latest_firmware_v2(microbit): """ There's NO need to use the DeviceFlasher if the board already has the latest firmware. In which case, just call copy_main. """ version_info = { "sysname": "microbit", "nodename": "microbit", "release": uflash.MICROPYTHON_V2_VERSION, "version": ("micro:bit v2.0.0-beta.3+d6c01d0 on 2020-12-21; " "MicroPython v1.13 on 2020-12-21"), "machine": "micro:bit with nRF52833", } with mock.patch("mu.modes.microbit.uflash.find_microbit", return_value="/path/microbit"), mock.patch( "mu.modes.microbit.microfs.version", return_value=version_info), mock.patch( "mu.modes.microbit.os.path.exists", return_value=True): view = mock.MagicMock() view.current_tab.text = mock.MagicMock(return_value="foo") view.show_message = mock.MagicMock() editor = mock.MagicMock() editor.minify = False editor.microbit_runtime = "" editor.current_device = microbit mm = MicrobitMode(editor, view) mm.copy_main = mock.MagicMock() mm.set_buttons = mock.MagicMock() mm.flash_start = mock.MagicMock() mm.flash() assert mm.flash_start.call_count == 0 mm.copy_main.assert_called_once_with(b"foo")