1# Copyright (c) 2020 Teslabs Engineering S.L. 2# 3# SPDX-License-Identifier: Apache-2.0 4 5import argparse 6from pathlib import Path 7from unittest.mock import patch, call 8 9import pytest 10 11from runners.stm32cubeprogrammer import STM32CubeProgrammerBinaryRunner 12from conftest import RC_KERNEL_HEX, RC_KERNEL_ELF 13 14 15CLI_PATH = Path("STM32_Programmer_CLI") 16"""Default CLI path used in tests.""" 17 18HOME_PATH = Path("/home", "test") 19"""Home path (used for Linux system CLI path).""" 20 21PROGRAMFILESX86_PATH = Path("C:", "Program Files (x86)") 22"""Program files x86 path (used for Windows system CLI path).""" 23 24ENVIRON = { 25 "PROGRAMFILES(X86)": str(PROGRAMFILESX86_PATH), 26} 27"""Environment (used for Windows system CLI path).""" 28 29LINUX_CLI_PATH = ( 30 HOME_PATH 31 / "STMicroelectronics" 32 / "STM32Cube" 33 / "STM32CubeProgrammer" 34 / "bin" 35 / "STM32_Programmer_CLI" 36) 37"""Linux CLI path.""" 38 39WINDOWS_CLI_PATH = ( 40 PROGRAMFILESX86_PATH 41 / "STMicroelectronics" 42 / "STM32Cube" 43 / "STM32CubeProgrammer" 44 / "bin" 45 / "STM32_Programmer_CLI.exe" 46) 47"""Windows CLI path.""" 48 49MACOS_CLI_PATH = ( 50 Path("/Applications") 51 / "STMicroelectronics" 52 / "STM32Cube" 53 / "STM32CubeProgrammer" 54 / "STM32CubeProgrammer.app" 55 / "Contents" 56 / "MacOs" 57 / "bin" 58 / "STM32_Programmer_CLI" 59) 60"""macOS CLI path.""" 61 62TEST_CASES = ( 63 { 64 "port": "swd", 65 "frequency": None, 66 "reset_mode": None, 67 "start_address": None, 68 "conn_modifiers": None, 69 "cli": CLI_PATH, 70 "use_elf": False, 71 "erase": False, 72 "extload": None, 73 "tool_opt": [], 74 "system": "", 75 "cli_path": str(CLI_PATH), 76 "calls": [ 77 [ 78 str(CLI_PATH), 79 "--connect", 80 "port=swd", 81 "--download", 82 RC_KERNEL_HEX, 83 "--start", 84 ], 85 ], 86 }, 87 { 88 "port": "swd", 89 "frequency": None, 90 "reset_mode": None, 91 "start_address": 0x8001000, 92 "conn_modifiers": None, 93 "cli": CLI_PATH, 94 "use_elf": False, 95 "erase": False, 96 "extload": None, 97 "tool_opt": [], 98 "system": "", 99 "cli_path": str(CLI_PATH), 100 "calls": [ 101 [ 102 str(CLI_PATH), 103 "--connect", 104 "port=swd", 105 "--download", 106 RC_KERNEL_HEX, 107 "--start", 108 "0x8001000" 109 ], 110 ], 111 }, 112 { 113 "port": "swd", 114 "frequency": "4000", 115 "reset_mode": None, 116 "start_address": None, 117 "conn_modifiers": None, 118 "cli": CLI_PATH, 119 "use_elf": False, 120 "erase": False, 121 "extload": None, 122 "tool_opt": [], 123 "system": "", 124 "cli_path": str(CLI_PATH), 125 "calls": [ 126 [ 127 str(CLI_PATH), 128 "--connect", 129 "port=swd freq=4000", 130 "--download", 131 RC_KERNEL_HEX, 132 "--start", 133 ], 134 ], 135 }, 136 { 137 "port": "swd", 138 "frequency": None, 139 "reset_mode": "hw", 140 "start_address": None, 141 "conn_modifiers": None, 142 "cli": CLI_PATH, 143 "use_elf": False, 144 "erase": False, 145 "extload": None, 146 "tool_opt": [], 147 "system": "", 148 "cli_path": str(CLI_PATH), 149 "calls": [ 150 [ 151 str(CLI_PATH), 152 "--connect", 153 "port=swd reset=HWrst", 154 "--download", 155 RC_KERNEL_HEX, 156 "--start", 157 ], 158 ], 159 }, 160 { 161 "port": "swd", 162 "frequency": None, 163 "reset_mode": "sw", 164 "start_address": None, 165 "conn_modifiers": None, 166 "cli": CLI_PATH, 167 "use_elf": False, 168 "erase": False, 169 "extload": None, 170 "tool_opt": [], 171 "system": "", 172 "cli_path": str(CLI_PATH), 173 "calls": [ 174 [ 175 str(CLI_PATH), 176 "--connect", 177 "port=swd reset=SWrst", 178 "--download", 179 RC_KERNEL_HEX, 180 "--start", 181 ], 182 ], 183 }, 184 { 185 "port": "swd", 186 "frequency": None, 187 "reset_mode": "core", 188 "start_address": None, 189 "conn_modifiers": None, 190 "cli": CLI_PATH, 191 "use_elf": False, 192 "erase": False, 193 "extload": None, 194 "tool_opt": [], 195 "system": "", 196 "cli_path": str(CLI_PATH), 197 "calls": [ 198 [ 199 str(CLI_PATH), 200 "--connect", 201 "port=swd reset=Crst", 202 "--download", 203 RC_KERNEL_HEX, 204 "--start", 205 ], 206 ], 207 }, 208 { 209 "port": "swd", 210 "frequency": None, 211 "reset_mode": None, 212 "start_address": None, 213 "conn_modifiers": "br=115200 sn=TEST", 214 "cli": CLI_PATH, 215 "use_elf": False, 216 "erase": False, 217 "extload": None, 218 "tool_opt": [], 219 "system": "", 220 "cli_path": str(CLI_PATH), 221 "calls": [ 222 [ 223 str(CLI_PATH), 224 "--connect", 225 "port=swd br=115200 sn=TEST", 226 "--download", 227 RC_KERNEL_HEX, 228 "--start", 229 ], 230 ], 231 }, 232 { 233 "port": "swd", 234 "frequency": None, 235 "reset_mode": None, 236 "start_address": None, 237 "conn_modifiers": None, 238 "cli": CLI_PATH, 239 "use_elf": True, 240 "erase": False, 241 "extload": None, 242 "tool_opt": [], 243 "system": "", 244 "cli_path": str(CLI_PATH), 245 "calls": [ 246 [ 247 str(CLI_PATH), 248 "--connect", 249 "port=swd", 250 "--download", 251 RC_KERNEL_ELF, 252 "--start", 253 ], 254 ], 255 }, 256 { 257 "port": "swd", 258 "frequency": None, 259 "reset_mode": None, 260 "start_address": None, 261 "conn_modifiers": None, 262 "cli": CLI_PATH, 263 "use_elf": False, 264 "erase": True, 265 "extload": None, 266 "tool_opt": [], 267 "system": "", 268 "cli_path": str(CLI_PATH), 269 "calls": [ 270 [str(CLI_PATH), "--connect", "port=swd", "--erase", "all",], 271 [ 272 str(CLI_PATH), 273 "--connect", 274 "port=swd", 275 "--download", 276 RC_KERNEL_HEX, 277 "--start", 278 ], 279 ], 280 }, 281 { 282 "port": "swd", 283 "frequency": None, 284 "reset_mode": None, 285 "start_address": None, 286 "conn_modifiers": None, 287 "cli": CLI_PATH, 288 "use_elf": False, 289 "erase": False, 290 "extload": None, 291 "tool_opt": ["--skipErase"], 292 "system": "", 293 "cli_path": str(CLI_PATH), 294 "calls": [ 295 [ 296 str(CLI_PATH), 297 "--connect", 298 "port=swd", 299 "--skipErase", 300 "--download", 301 RC_KERNEL_HEX, 302 "--start", 303 ], 304 ], 305 }, 306 { 307 "port": "swd", 308 "frequency": None, 309 "reset_mode": None, 310 "start_address": None, 311 "conn_modifiers": None, 312 "cli": None, 313 "use_elf": False, 314 "erase": False, 315 "extload": None, 316 "tool_opt": [], 317 "system": "Linux", 318 "cli_path": str(LINUX_CLI_PATH), 319 "calls": [ 320 [ 321 str(LINUX_CLI_PATH), 322 "--connect", 323 "port=swd", 324 "--download", 325 RC_KERNEL_HEX, 326 "--start", 327 ], 328 ], 329 }, 330 { 331 "port": "swd", 332 "frequency": None, 333 "reset_mode": None, 334 "start_address": None, 335 "conn_modifiers": None, 336 "cli": None, 337 "use_elf": False, 338 "erase": False, 339 "extload": None, 340 "tool_opt": [], 341 "system": "Darwin", 342 "cli_path": str(MACOS_CLI_PATH), 343 "calls": [ 344 [ 345 str(MACOS_CLI_PATH), 346 "--connect", 347 "port=swd", 348 "--download", 349 RC_KERNEL_HEX, 350 "--start", 351 ], 352 ], 353 }, 354 { 355 "port": "swd", 356 "frequency": None, 357 "reset_mode": None, 358 "start_address": None, 359 "conn_modifiers": None, 360 "cli": None, 361 "use_elf": False, 362 "erase": False, 363 "extload": None, 364 "tool_opt": [], 365 "system": "Windows", 366 "cli_path": str(WINDOWS_CLI_PATH), 367 "calls": [ 368 [ 369 str(WINDOWS_CLI_PATH), 370 "--connect", 371 "port=swd", 372 "--download", 373 RC_KERNEL_HEX, 374 "--start", 375 ], 376 ], 377 }, 378) 379"""Test cases.""" 380 381 382@pytest.mark.parametrize("tc", TEST_CASES) 383@patch("runners.stm32cubeprogrammer.platform.system") 384@patch("runners.stm32cubeprogrammer.Path.home", return_value=HOME_PATH) 385@patch("runners.stm32cubeprogrammer.Path.exists", return_value=True) 386@patch.dict("runners.stm32cubeprogrammer.os.environ", ENVIRON) 387@patch("runners.core.ZephyrBinaryRunner.require") 388@patch("runners.stm32cubeprogrammer.STM32CubeProgrammerBinaryRunner.check_call") 389def test_stm32cubeprogrammer_init( 390 check_call, require, path_exists, path_home, system, tc, runner_config 391): 392 """Tests that ``STM32CubeProgrammerBinaryRunner`` class can be initialized 393 and that ``flash`` command works as expected. 394 """ 395 396 system.return_value = tc["system"] 397 398 runner = STM32CubeProgrammerBinaryRunner( 399 cfg=runner_config, 400 port=tc["port"], 401 frequency=tc["frequency"], 402 reset_mode=tc["reset_mode"], 403 start_address=tc["start_address"], 404 conn_modifiers=tc["conn_modifiers"], 405 cli=tc["cli"], 406 use_elf=tc["use_elf"], 407 erase=tc["erase"], 408 extload=tc["extload"], 409 tool_opt=tc["tool_opt"], 410 ) 411 412 runner.run("flash") 413 414 require.assert_called_with(tc["cli_path"]) 415 assert check_call.call_args_list == [call(x) for x in tc["calls"]] 416 417 418@pytest.mark.parametrize("tc", TEST_CASES) 419@patch("runners.stm32cubeprogrammer.platform.system") 420@patch("runners.stm32cubeprogrammer.Path.home", return_value=HOME_PATH) 421@patch("runners.stm32cubeprogrammer.Path.exists", return_value=True) 422@patch.dict("runners.stm32cubeprogrammer.os.environ", ENVIRON) 423@patch("runners.core.ZephyrBinaryRunner.require") 424@patch("runners.stm32cubeprogrammer.STM32CubeProgrammerBinaryRunner.check_call") 425def test_stm32cubeprogrammer_create( 426 check_call, require, path_exists, path_home, system, tc, runner_config 427): 428 """Tests that ``STM32CubeProgrammerBinaryRunner`` class can be created using 429 the ``create`` factory method and that ``flash`` command works as expected. 430 """ 431 432 system.return_value = tc["system"] 433 434 args = ["--port", tc["port"]] 435 if tc["frequency"]: 436 args.extend(["--frequency", tc["frequency"]]) 437 if tc["reset_mode"]: 438 args.extend(["--reset-mode", tc["reset_mode"]]) 439 if tc["start_address"]: 440 args.extend(["--start-address", str(tc["start_address"])]) 441 if tc["conn_modifiers"]: 442 args.extend(["--conn-modifiers", tc["conn_modifiers"]]) 443 if tc["cli"]: 444 args.extend(["--cli", str(tc["cli"])]) 445 if tc["use_elf"]: 446 args.extend(["--use-elf"]) 447 if tc["erase"]: 448 args.append("--erase") 449 if tc["extload"]: 450 args.extend(["--extload", tc["extload"]]) 451 if tc["tool_opt"]: 452 args.extend(["--tool-opt", " " + tc["tool_opt"][0]]) 453 454 parser = argparse.ArgumentParser(allow_abbrev=False) 455 STM32CubeProgrammerBinaryRunner.add_parser(parser) 456 arg_namespace = parser.parse_args(args) 457 458 runner = STM32CubeProgrammerBinaryRunner.create(runner_config, arg_namespace) 459 runner.run("flash") 460 461 require.assert_called_with(tc["cli_path"]) 462 assert check_call.call_args_list == [call(x) for x in tc["calls"]] 463