# Copyright (c) 2018 Foundries.io # Copyright (c) 2019 Nordic Semiconductor ASA. # # SPDX-License-Identifier: Apache-2.0 import argparse from unittest.mock import patch, call import os import pytest from runners import blackmagicprobe from runners.blackmagicprobe import BlackMagicProbeRunner from conftest import RC_KERNEL_ELF, RC_GDB import serial.tools.list_ports TEST_GDB_SERIAL = 'test-gdb-serial' # Expected subprocesses to be run for each command. Using the # runner_config fixture (and always specifying gdb-serial) means we # don't get 100% coverage, but it's a starting out point. EXPECTED_COMMANDS = { 'attach': ([RC_GDB, '-ex', "set confirm off", '-ex', "target extended-remote {}".format(TEST_GDB_SERIAL), '-ex', "monitor swdp_scan", '-ex', "attach 1", '-ex', "file {}".format(RC_KERNEL_ELF)],), 'debug': ([RC_GDB, '-ex', "set confirm off", '-ex', "target extended-remote {}".format(TEST_GDB_SERIAL), '-ex', "monitor swdp_scan", '-ex', "attach 1", '-ex', "file {}".format(RC_KERNEL_ELF), '-ex', "load {}".format(RC_KERNEL_ELF)],), 'flash': ([RC_GDB, '-ex', "set confirm off", '-ex', "target extended-remote {}".format(TEST_GDB_SERIAL), '-ex', "monitor swdp_scan", '-ex', "attach 1", '-ex', "load {}".format(RC_KERNEL_ELF), '-ex', "kill", '-ex', "quit", '-silent'],), } EXPECTED_CONNECT_SRST_COMMAND = { 'attach': 'monitor connect_rst disable', 'debug': 'monitor connect_rst enable', 'flash': 'monitor connect_rst enable', } def require_patch(program): assert program == RC_GDB @pytest.mark.parametrize('command', EXPECTED_COMMANDS) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.check_call') def test_blackmagicprobe_init(cc, req, command, runner_config): '''Test commands using a runner created by constructor.''' runner = BlackMagicProbeRunner(runner_config, TEST_GDB_SERIAL) runner.run(command) assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS[command]] @pytest.mark.parametrize('command', EXPECTED_COMMANDS) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.check_call') def test_blackmagicprobe_create(cc, req, command, runner_config): '''Test commands using a runner created from command line parameters.''' args = ['--gdb-serial', TEST_GDB_SERIAL] parser = argparse.ArgumentParser(allow_abbrev=False) BlackMagicProbeRunner.add_parser(parser) arg_namespace = parser.parse_args(args) runner = BlackMagicProbeRunner.create(runner_config, arg_namespace) runner.run(command) assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS[command]] @pytest.mark.parametrize('command', EXPECTED_CONNECT_SRST_COMMAND) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.check_call') def test_blackmagicprobe_connect_rst(cc, req, command, runner_config): '''Test that commands list the correct connect_rst value when enabled.''' args = ['--gdb-serial', TEST_GDB_SERIAL, '--connect-rst'] parser = argparse.ArgumentParser(allow_abbrev=False) BlackMagicProbeRunner.add_parser(parser) arg_namespace = parser.parse_args(args) runner = BlackMagicProbeRunner.create(runner_config, arg_namespace) runner.run(command) expected = EXPECTED_CONNECT_SRST_COMMAND[command] assert expected in cc.call_args_list[0][0][0] @pytest.mark.parametrize('arg, env, expected', [ # Argument has priority ('/dev/XXX', None, '/dev/XXX'), ('/dev/XXX', '/dev/YYYY', '/dev/XXX'), # Then BMP_GDB_SERIAL env variable (None, '/dev/XXX', '/dev/XXX'), ]) def test_blackmagicprobe_gdb_serial_generic(arg, env, expected): if env: os.environ['BMP_GDB_SERIAL'] = env else: if 'BMP_GDB_SERIAL' in os.environ: os.environ.pop('BMP_GDB_SERIAL') ret = blackmagicprobe.blackmagicprobe_gdb_serial(arg) assert expected == ret @pytest.mark.parametrize('known_path, comports, globs, expected', [ (True, False, ['/dev/ttyACM0', '/dev/ttyACM1'], blackmagicprobe.DEFAULT_LINUX_BMP_PATH), (False, True, [], '/dev/ttyACM3'), (False, False, ['/dev/ttyACM0', '/dev/ttyACM1'], '/dev/ttyACM0'), (False, False, ['/dev/ttyACM1', '/dev/ttyACM0'], '/dev/ttyACM0'), ]) @patch('serial.tools.list_ports.comports') @patch('os.path.exists') @patch('glob.glob') def test_blackmagicprobe_gdb_serial_linux(gg, ope, stlpc, known_path, comports, globs, expected): gg.return_value = globs ope.return_value = known_path if comports: fake_comport1 = serial.tools.list_ports_common.ListPortInfo( '/dev/ttyACM1') fake_comport1.interface = 'something' fake_comport2 = serial.tools.list_ports_common.ListPortInfo( '/dev/ttyACM2') fake_comport2.interface = None fake_comport3 = serial.tools.list_ports_common.ListPortInfo( '/dev/ttyACM3') fake_comport3.interface = blackmagicprobe.BMP_GDB_INTERFACE stlpc.return_value = [fake_comport1, fake_comport2, fake_comport3] else: stlpc.return_value = [] ret = blackmagicprobe.blackmagicprobe_gdb_serial_linux() assert expected == ret @pytest.mark.parametrize('comports, globs, expected', [ (True, [], '/dev/cu.usbmodem3'), (False, ['/dev/cu.usbmodemAABBCC0', '/dev/cu.usbmodemAABBCC1'], '/dev/cu.usbmodemAABBCC0'), (False, ['/dev/cu.usbmodemAABBCC1', '/dev/cu.usbmodemAABBCC0'], '/dev/cu.usbmodemAABBCC0'), ]) @patch('serial.tools.list_ports.comports') @patch('glob.glob') def test_blackmagicprobe_gdb_serial_darwin(gg, stlpc, comports, globs, expected): gg.return_value = globs if comports: fake_comport1 = serial.tools.list_ports_common.ListPortInfo( '/dev/cu.usbmodem1') fake_comport1.description = 'unrelated' fake_comport2 = serial.tools.list_ports_common.ListPortInfo( '/dev/cu.usbmodem2') fake_comport2.description = None fake_comport3 = serial.tools.list_ports_common.ListPortInfo( '/dev/cu.usbmodem3') fake_comport3.description = f'{blackmagicprobe.BMP_GDB_PRODUCT} v1234' fake_comport4 = serial.tools.list_ports_common.ListPortInfo( '/dev/cu.usbmodem4') fake_comport4.description = f'{blackmagicprobe.BMP_GDB_PRODUCT} v1234' stlpc.return_value = [fake_comport1, fake_comport2, fake_comport4, fake_comport3] else: stlpc.return_value = [] ret = blackmagicprobe.blackmagicprobe_gdb_serial_darwin() assert expected == ret @pytest.mark.parametrize('comports, expected', [ (True, 'COM4'), (False, 'COM1'), ]) @patch('serial.tools.list_ports.comports') def test_blackmagicprobe_gdb_serial_win32(stlpc, comports, expected): if comports: fake_comport1 = serial.tools.list_ports_common.ListPortInfo('COM2') fake_comport1.vid = 123 fake_comport1.pid = 456 fake_comport2 = serial.tools.list_ports_common.ListPortInfo('COM3') fake_comport2.vid = None fake_comport2.pid = None fake_comport3 = serial.tools.list_ports_common.ListPortInfo('COM4') fake_comport3.vid = blackmagicprobe.BMP_GDB_VID fake_comport3.pid = blackmagicprobe.BMP_GDB_PID fake_comport4 = serial.tools.list_ports_common.ListPortInfo('COM5') fake_comport4.vid = blackmagicprobe.BMP_GDB_VID fake_comport4.pid = blackmagicprobe.BMP_GDB_PID stlpc.return_value = [fake_comport1, fake_comport2, fake_comport4, fake_comport3] else: stlpc.return_value = [] ret = blackmagicprobe.blackmagicprobe_gdb_serial_win32() assert expected == ret