1# Copyright (c) 2020 Teslabs Engineering S.L. 2# 3# SPDX-License-Identifier: Apache-2.0 4 5import argparse 6import os 7from pathlib import Path 8from unittest.mock import patch, call 9 10import pytest 11 12from runners.stm32cubeprogrammer import STM32CubeProgrammerBinaryRunner 13from conftest import RC_KERNEL_HEX, RC_KERNEL_ELF, RC_KERNEL_BIN 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 "download_address": None, 68 "start_address": None, 69 "conn_modifiers": None, 70 "start_modifiers": [], 71 "download_modifiers": [], 72 "cli": CLI_PATH, 73 "use_elf": False, 74 "erase": False, 75 "extload": None, 76 "tool_opt": [], 77 "system": "", 78 "cli_path": str(CLI_PATH), 79 "calls": [ 80 [ 81 str(CLI_PATH), 82 "--connect", 83 "port=swd", 84 "--download", 85 RC_KERNEL_HEX, 86 "--start", 87 ], 88 ], 89 }, 90 { 91 "port": "swd", 92 "frequency": None, 93 "reset_mode": None, 94 "download_address": None, 95 "start_address": 0x8001000, 96 "conn_modifiers": None, 97 "start_modifiers": [], 98 "download_modifiers": [], 99 "cli": CLI_PATH, 100 "use_elf": False, 101 "erase": False, 102 "extload": None, 103 "tool_opt": [], 104 "system": "", 105 "cli_path": str(CLI_PATH), 106 "calls": [ 107 [ 108 str(CLI_PATH), 109 "--connect", 110 "port=swd", 111 "--download", 112 RC_KERNEL_HEX, 113 "--start", 114 "0x8001000" 115 ], 116 ], 117 }, 118 { 119 "port": "swd", 120 "frequency": "4000", 121 "reset_mode": None, 122 "download_address": None, 123 "start_address": None, 124 "conn_modifiers": None, 125 "start_modifiers": [], 126 "download_modifiers": [], 127 "cli": CLI_PATH, 128 "use_elf": False, 129 "erase": False, 130 "extload": None, 131 "tool_opt": [], 132 "system": "", 133 "cli_path": str(CLI_PATH), 134 "calls": [ 135 [ 136 str(CLI_PATH), 137 "--connect", 138 "port=swd freq=4000", 139 "--download", 140 RC_KERNEL_HEX, 141 "--start", 142 ], 143 ], 144 }, 145 { 146 "port": "swd", 147 "frequency": None, 148 "reset_mode": "hw", 149 "download_address": None, 150 "start_address": None, 151 "conn_modifiers": None, 152 "start_modifiers": [], 153 "download_modifiers": [], 154 "cli": CLI_PATH, 155 "use_elf": False, 156 "erase": False, 157 "extload": None, 158 "tool_opt": [], 159 "system": "", 160 "cli_path": str(CLI_PATH), 161 "calls": [ 162 [ 163 str(CLI_PATH), 164 "--connect", 165 "port=swd reset=HWrst", 166 "--download", 167 RC_KERNEL_HEX, 168 "--start", 169 ], 170 ], 171 }, 172 { 173 "port": "swd", 174 "frequency": None, 175 "reset_mode": "sw", 176 "download_address": None, 177 "start_address": None, 178 "conn_modifiers": None, 179 "start_modifiers": [], 180 "download_modifiers": [], 181 "cli": CLI_PATH, 182 "use_elf": False, 183 "erase": False, 184 "extload": None, 185 "tool_opt": [], 186 "system": "", 187 "cli_path": str(CLI_PATH), 188 "calls": [ 189 [ 190 str(CLI_PATH), 191 "--connect", 192 "port=swd reset=SWrst", 193 "--download", 194 RC_KERNEL_HEX, 195 "--start", 196 ], 197 ], 198 }, 199 { 200 "port": "swd", 201 "frequency": None, 202 "reset_mode": "core", 203 "download_address": None, 204 "start_address": None, 205 "conn_modifiers": None, 206 "start_modifiers": [], 207 "download_modifiers": [], 208 "cli": CLI_PATH, 209 "use_elf": False, 210 "erase": False, 211 "extload": None, 212 "tool_opt": [], 213 "system": "", 214 "cli_path": str(CLI_PATH), 215 "calls": [ 216 [ 217 str(CLI_PATH), 218 "--connect", 219 "port=swd reset=Crst", 220 "--download", 221 RC_KERNEL_HEX, 222 "--start", 223 ], 224 ], 225 }, 226 { 227 "port": "swd", 228 "frequency": None, 229 "reset_mode": None, 230 "download_address": None, 231 "start_address": None, 232 "conn_modifiers": "br=115200 sn=TEST", 233 "start_modifiers": [], 234 "download_modifiers": [], 235 "cli": CLI_PATH, 236 "use_elf": False, 237 "erase": False, 238 "extload": None, 239 "tool_opt": [], 240 "system": "", 241 "cli_path": str(CLI_PATH), 242 "calls": [ 243 [ 244 str(CLI_PATH), 245 "--connect", 246 "port=swd br=115200 sn=TEST", 247 "--download", 248 RC_KERNEL_HEX, 249 "--start", 250 ], 251 ], 252 }, 253 { 254 "port": "swd", 255 "frequency": None, 256 "reset_mode": None, 257 "download_address": None, 258 "start_address": None, 259 "conn_modifiers": None, 260 "start_modifiers": [], 261 "download_modifiers": [], 262 "cli": CLI_PATH, 263 "use_elf": True, 264 "erase": False, 265 "extload": None, 266 "tool_opt": [], 267 "system": "", 268 "cli_path": str(CLI_PATH), 269 "calls": [ 270 [ 271 str(CLI_PATH), 272 "--connect", 273 "port=swd", 274 "--download", 275 RC_KERNEL_ELF, 276 "--start", 277 ], 278 ], 279 }, 280 { 281 "port": "swd", 282 "frequency": None, 283 "reset_mode": None, 284 "download_address": None, 285 "start_address": None, 286 "conn_modifiers": None, 287 "start_modifiers": [], 288 "download_modifiers": [], 289 "cli": CLI_PATH, 290 "use_elf": False, 291 "erase": True, 292 "extload": None, 293 "tool_opt": [], 294 "system": "", 295 "cli_path": str(CLI_PATH), 296 "calls": [ 297 [str(CLI_PATH), "--connect", "port=swd", "--erase", "all",], 298 [ 299 str(CLI_PATH), 300 "--connect", 301 "port=swd", 302 "--download", 303 RC_KERNEL_HEX, 304 "--start", 305 ], 306 ], 307 }, 308 { 309 "port": "swd", 310 "frequency": None, 311 "reset_mode": None, 312 "download_address": None, 313 "start_address": None, 314 "conn_modifiers": None, 315 "start_modifiers": [], 316 "download_modifiers": [], 317 "cli": CLI_PATH, 318 "use_elf": False, 319 "erase": False, 320 "extload": None, 321 "tool_opt": ["--skipErase"], 322 "system": "", 323 "cli_path": str(CLI_PATH), 324 "calls": [ 325 [ 326 str(CLI_PATH), 327 "--connect", 328 "port=swd", 329 "--skipErase", 330 "--download", 331 RC_KERNEL_HEX, 332 "--start", 333 ], 334 ], 335 }, 336 { 337 "port": "swd", 338 "frequency": None, 339 "reset_mode": None, 340 "download_address": None, 341 "start_address": None, 342 "conn_modifiers": None, 343 "start_modifiers": [], 344 "download_modifiers": [], 345 "cli": None, 346 "use_elf": False, 347 "erase": False, 348 "extload": None, 349 "tool_opt": [], 350 "system": "Linux", 351 "cli_path": str(LINUX_CLI_PATH), 352 "calls": [ 353 [ 354 str(LINUX_CLI_PATH), 355 "--connect", 356 "port=swd", 357 "--download", 358 RC_KERNEL_HEX, 359 "--start", 360 ], 361 ], 362 }, 363 { 364 "port": "swd", 365 "frequency": None, 366 "reset_mode": None, 367 "download_address": None, 368 "start_address": None, 369 "conn_modifiers": None, 370 "start_modifiers": [], 371 "download_modifiers": [], 372 "cli": None, 373 "use_elf": False, 374 "erase": False, 375 "extload": None, 376 "tool_opt": [], 377 "system": "Darwin", 378 "cli_path": str(MACOS_CLI_PATH), 379 "calls": [ 380 [ 381 str(MACOS_CLI_PATH), 382 "--connect", 383 "port=swd", 384 "--download", 385 RC_KERNEL_HEX, 386 "--start", 387 ], 388 ], 389 }, 390 { 391 "port": "swd", 392 "frequency": None, 393 "reset_mode": None, 394 "download_address": None, 395 "start_address": None, 396 "conn_modifiers": None, 397 "start_modifiers": [], 398 "download_modifiers": [], 399 "cli": None, 400 "use_elf": False, 401 "erase": False, 402 "extload": None, 403 "tool_opt": [], 404 "system": "Windows", 405 "cli_path": str(WINDOWS_CLI_PATH), 406 "calls": [ 407 [ 408 str(WINDOWS_CLI_PATH), 409 "--connect", 410 "port=swd", 411 "--download", 412 RC_KERNEL_HEX, 413 "--start", 414 ], 415 ], 416 }, 417 { 418 "port": "swd", 419 "frequency": None, 420 "reset_mode": None, 421 "download_address": 0x80000000, 422 "start_address": None, 423 "conn_modifiers": None, 424 "start_modifiers": ["noack"], 425 "download_modifiers": ["0x1"], 426 "cli": CLI_PATH, 427 "use_elf": False, 428 "erase": False, 429 "extload": None, 430 "tool_opt": [], 431 "system": "", 432 "cli_path": str(CLI_PATH), 433 "calls": [ 434 [ 435 str(CLI_PATH), 436 "--connect", 437 "port=swd", 438 "--download", 439 RC_KERNEL_BIN, 440 "0x80000000", 441 "0x1", 442 "--start", 443 "noack", 444 ], 445 ], 446 }, 447) 448"""Test cases.""" 449 450os_path_isfile = os.path.isfile 451 452def os_path_isfile_patch(filename): 453 if filename == RC_KERNEL_BIN: 454 return True 455 return os_path_isfile(filename) 456 457@pytest.mark.parametrize("tc", TEST_CASES) 458@patch("runners.stm32cubeprogrammer.platform.system") 459@patch("runners.stm32cubeprogrammer.Path.home", return_value=HOME_PATH) 460@patch("runners.stm32cubeprogrammer.Path.exists", return_value=True) 461@patch.dict("runners.stm32cubeprogrammer.os.environ", ENVIRON) 462@patch("runners.core.ZephyrBinaryRunner.require") 463@patch("runners.stm32cubeprogrammer.STM32CubeProgrammerBinaryRunner.check_call") 464@patch("os.path.isfile", side_effect=os_path_isfile_patch) 465def test_stm32cubeprogrammer_init( 466 os_path_isfile_patch, 467 check_call, require, path_exists, path_home, system, tc, runner_config 468): 469 """Tests that ``STM32CubeProgrammerBinaryRunner`` class can be initialized 470 and that ``flash`` command works as expected. 471 """ 472 473 system.return_value = tc["system"] 474 475 runner = STM32CubeProgrammerBinaryRunner( 476 cfg=runner_config, 477 port=tc["port"], 478 frequency=tc["frequency"], 479 reset_mode=tc["reset_mode"], 480 download_address=tc["download_address"], 481 download_modifiers=tc["download_modifiers"], 482 start_address=tc["start_address"], 483 start_modifiers=tc["start_modifiers"], 484 conn_modifiers=tc["conn_modifiers"], 485 cli=tc["cli"], 486 use_elf=tc["use_elf"], 487 erase=tc["erase"], 488 extload=tc["extload"], 489 tool_opt=tc["tool_opt"], 490 ) 491 492 runner.run("flash") 493 494 require.assert_called_with(tc["cli_path"]) 495 assert check_call.call_args_list == [call(x) for x in tc["calls"]] 496 497 498@pytest.mark.parametrize("tc", TEST_CASES) 499@patch("runners.stm32cubeprogrammer.platform.system") 500@patch("runners.stm32cubeprogrammer.Path.home", return_value=HOME_PATH) 501@patch("runners.stm32cubeprogrammer.Path.exists", return_value=True) 502@patch.dict("runners.stm32cubeprogrammer.os.environ", ENVIRON) 503@patch("runners.core.ZephyrBinaryRunner.require") 504@patch("runners.stm32cubeprogrammer.STM32CubeProgrammerBinaryRunner.check_call") 505@patch("os.path.isfile", side_effect=os_path_isfile_patch) 506def test_stm32cubeprogrammer_create( 507 os_path_isfile_patch, 508 check_call, require, path_exists, path_home, system, tc, runner_config 509): 510 """Tests that ``STM32CubeProgrammerBinaryRunner`` class can be created using 511 the ``create`` factory method and that ``flash`` command works as expected. 512 """ 513 514 system.return_value = tc["system"] 515 516 args = ["--port", tc["port"]] 517 if tc["frequency"]: 518 args.extend(["--frequency", tc["frequency"]]) 519 if tc["reset_mode"]: 520 args.extend(["--reset-mode", tc["reset_mode"]]) 521 if tc["download_address"]: 522 args.extend(["--download-address", str(tc["download_address"])]) 523 if tc["start_address"]: 524 args.extend(["--start-address", str(tc["start_address"])]) 525 if tc["conn_modifiers"]: 526 args.extend(["--conn-modifiers", tc["conn_modifiers"]]) 527 if tc["cli"]: 528 args.extend(["--cli", str(tc["cli"])]) 529 if tc["use_elf"]: 530 args.extend(["--use-elf"]) 531 if tc["erase"]: 532 args.append("--erase") 533 if tc["extload"]: 534 args.extend(["--extload", tc["extload"]]) 535 if tc["tool_opt"]: 536 args.extend(["--tool-opt", " " + tc["tool_opt"][0]]) 537 if tc["download_modifiers"]: 538 args.extend(["--download-modifiers", " " + tc["download_modifiers"][0]]) 539 if tc["start_modifiers"]: 540 args.extend(["--start-modifiers", " " + tc["start_modifiers"][0]]) 541 542 parser = argparse.ArgumentParser(allow_abbrev=False) 543 STM32CubeProgrammerBinaryRunner.add_parser(parser) 544 arg_namespace = parser.parse_args(args) 545 546 runner = STM32CubeProgrammerBinaryRunner.create(runner_config, arg_namespace) 547 runner.run("flash") 548 549 require.assert_called_with(tc["cli_path"]) 550 assert check_call.call_args_list == [call(x) for x in tc["calls"]] 551