Skip to content

Commit 9b2e43e

Browse files
committed
add cli_test and refactor
1 parent 6dc1776 commit 9b2e43e

File tree

7 files changed

+317
-179
lines changed

7 files changed

+317
-179
lines changed

src/mpflash/mpflash/cli_flash.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ def cli_flash_board(**kwargs):
130130
if len(params.versions) > 1:
131131
log.error(f"Only one version can be flashed at a time, not {params.versions}")
132132
raise MPFlashError("Only one version can be flashed at a time")
133-
if len(params.boards) > 1:
134-
log.error(f"Only one board can be flashed at a time, not {params.boards}")
135-
raise MPFlashError("Only one board can be flashed at a time")
133+
# if len(params.boards) > 1:
134+
# log.error(f"Only one board can be flashed at a time, not {params.boards}")
135+
# raise MPFlashError("Only one board can be flashed at a time")
136136

137137
params.versions = [clean_version(v) for v in params.versions]
138138
worklist: WorkList = []

src/mpflash/mpflash/cli_group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
def cb_verbose(ctx, param, value):
1313
"""Callback to set the log level to DEBUG if verbose is set"""
14-
if value:
14+
if value and not config.quiet:
1515
set_loglevel("DEBUG")
1616
config.verbose = True
1717
else:
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from pathlib import Path
2+
from typing import List
3+
4+
import pytest
5+
from click.testing import CliRunner
6+
from mock import Mock
7+
from pytest_mock import MockerFixture
8+
9+
# # module under test :
10+
from mpflash import cli_main
11+
from mpflash.ask_input import DownloadParams
12+
from mpflash.mpremoteboard import MPRemoteBoard
13+
14+
# mark all tests
15+
pytestmark = pytest.mark.mpflash
16+
17+
18+
##########################################################################################
19+
# download
20+
21+
22+
@pytest.mark.parametrize(
23+
"id, ex_code, args",
24+
[
25+
("10", 0, ["download"]),
26+
("20", 0, ["download", "--destination", "firmware"]),
27+
("30", 0, ["download", "--version", "1.22.0"]),
28+
("31", 0, ["download", "--version", "stable"]),
29+
("32", 0, ["download", "--version", "stable", "--version", "1.22.0"]),
30+
("40", 0, ["download", "--board", "ESP32_GENERIC"]),
31+
("41", 0, ["download", "--board", "?"]),
32+
("42", 0, ["download", "--board", "?", "--board", "ESP32_GENERIC"]),
33+
("50", 0, ["download", "--destination", "firmware", "--version", "1.22.0", "--board", "ESP32_GENERIC"]),
34+
("60", 0, ["download", "--no-clean"]),
35+
("61", 0, ["download", "--clean"]),
36+
("62", 0, ["download", "--force"]),
37+
],
38+
)
39+
def test_mpflash_download(id, ex_code, args: List[str], mocker: MockerFixture):
40+
def fake_ask_missing_params(params: DownloadParams, action: str = "download") -> DownloadParams:
41+
return params
42+
43+
m_connected_ports_boards = mocker.patch(
44+
"mpflash.cli_download.connected_ports_boards",
45+
return_value=(["esp32"], ["ESP32_GENERIC"]),
46+
autospec=True,
47+
)
48+
m_download = mocker.patch("mpflash.cli_download.download", return_value=None, autospec=True)
49+
m_ask_missing_params = mocker.patch(
50+
"mpflash.cli_download.ask_missing_params",
51+
Mock(side_effect=fake_ask_missing_params),
52+
)
53+
54+
runner = CliRunner()
55+
result = runner.invoke(cli_main.cli, args)
56+
assert result.exit_code == ex_code
57+
if not "--board" in args:
58+
m_connected_ports_boards.assert_called_once()
59+
m_ask_missing_params.assert_called_once()
60+
m_download.assert_called_once()
61+
62+
if "--clean" in args:
63+
assert m_download.call_args.args[5] == True
64+
if "--no-clean" in args:
65+
assert m_download.call_args.args[5] == False
66+
else:
67+
assert m_download.call_args.args[5] == True
68+
69+
if "--force" in args:
70+
assert m_download.call_args.args[4] == True
71+
else:
72+
assert m_download.call_args.args[4] == False
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from pathlib import Path
2+
from typing import List
3+
4+
import pytest
5+
from click.testing import CliRunner
6+
from mock import Mock
7+
from pytest_mock import MockerFixture
8+
9+
# # module under test :
10+
from mpflash import cli_main
11+
from mpflash.ask_input import DownloadParams
12+
from mpflash.mpremoteboard import MPRemoteBoard
13+
14+
# mark all tests
15+
pytestmark = pytest.mark.mpflash
16+
17+
18+
##########################################################################################
19+
def fakeboard(serialport="COM99"):
20+
fake = MPRemoteBoard(serialport)
21+
fake.connected = True
22+
fake.family = "micropython"
23+
fake.port = "esp32"
24+
fake.board = "ESP32_GENERIC"
25+
fake.version = "1.22.0"
26+
fake.cpu = "ESP32"
27+
return fake
28+
29+
30+
def fake_ask_missing_params(params: DownloadParams, action: str = "flash") -> DownloadParams:
31+
# no input during tests
32+
return params
33+
34+
35+
##########################################################################################
36+
# flash
37+
38+
39+
@pytest.mark.parametrize(
40+
"id, ex_code, args",
41+
[
42+
("10", 0, ["flash"]),
43+
("20", 0, ["flash", "--version", "1.22.0"]),
44+
("21", 0, ["flash", "--version", "stable"]),
45+
("30", 0, ["flash", "--board", "ESP32_GENERIC"]),
46+
("31", 0, ["flash", "--board", "?"]),
47+
("40", 0, ["flash", "--no-bootloader"]),
48+
# faulty
49+
# ("81", -1, ["flash", "--board", "RPI_PICO", "--board", "ESP32_GENERIC"]),
50+
# ("82", -1, ["flash", "--version", "preview", "--version", "1.22.0"]),
51+
],
52+
)
53+
@pytest.mark.parametrize("serialport", ["COM99"])
54+
def test_mpflash_flash(id, ex_code, args: List[str], mocker: MockerFixture, serialport: str):
55+
56+
# fake COM99 as connected board
57+
fake = fakeboard(serialport)
58+
59+
m_mpr_connected = mocker.patch("mpflash.worklist.MPRemoteBoard", return_value=fake)
60+
m_mpr_connected = mocker.patch("mpflash.worklist.MPRemoteBoard.connected_boards", return_value=fake.serialport)
61+
62+
m_connected_ports_boards = mocker.patch(
63+
"mpflash.cli_flash.connected_ports_boards",
64+
return_value=(["esp32"], ["ESP32_GENERIC"]),
65+
autospec=True,
66+
)
67+
m_flash_list = mocker.patch("mpflash.cli_flash.flash_list", return_value=None, autospec=True)
68+
m_ask_missing_params = mocker.patch(
69+
"mpflash.cli_flash.ask_missing_params",
70+
Mock(side_effect=fake_ask_missing_params),
71+
)
72+
73+
runner = CliRunner()
74+
result = runner.invoke(cli_main.cli, args)
75+
76+
if not "--board" in args:
77+
m_connected_ports_boards.assert_called_once()
78+
79+
m_ask_missing_params.assert_called_once()
80+
m_mpr_connected.assert_called_once()
81+
# m_flash_list.assert_called_once()
82+
assert result.exit_code == ex_code
83+
84+
85+
# TODO : Add more tests scenarios for flash
86+
87+
88+
@pytest.mark.parametrize(
89+
"id, serialports, ports, boards",
90+
[
91+
("one", ["COM99"], ["esp32"], ["ESP32_GENERIC"]),
92+
("multiple", ["COM99", "COM100"], ["esp32", "samd"], ["ESP32_GENERIC", "SEEED_WIO_TERMINAL"]),
93+
("None", [], [], []),
94+
("linux", ["/dev/ttyusb0"], ["rp2"], ["ARDUINO_NANO_RP2040_CONNECT"]),
95+
],
96+
)
97+
def test_mpflash_connected_boards(
98+
id,
99+
serialports: List[str],
100+
ports: List[str],
101+
boards: List[str],
102+
mocker: MockerFixture,
103+
):
104+
# no boards specified - detect connected boards
105+
args = ["flash"]
106+
107+
fakes = [fakeboard(port) for port in serialports]
108+
109+
m_connected_ports_boards = mocker.patch(
110+
"mpflash.cli_flash.connected_ports_boards",
111+
return_value=(ports, boards),
112+
autospec=True,
113+
)
114+
m_flash_list = mocker.patch("mpflash.cli_flash.flash_list", return_value=None, autospec=True)
115+
m_ask_missing_params = mocker.patch(
116+
"mpflash.cli_flash.ask_missing_params",
117+
Mock(side_effect=fake_ask_missing_params),
118+
)
119+
120+
m_full_auto_worklist = mocker.patch("mpflash.cli_flash.full_auto_worklist", return_value=[])
121+
m_manual_worklist = mocker.patch("mpflash.cli_flash.manual_worklist", return_value=[])
122+
m_single_auto_worklist = mocker.patch("mpflash.cli_flash.single_auto_worklist", return_value=[])
123+
124+
runner = CliRunner()
125+
result = runner.invoke(cli_main.cli, args)
126+
127+
if serialports:
128+
m_full_auto_worklist.assert_called_once()
129+
m_manual_worklist.assert_not_called()
130+
m_single_auto_worklist.assert_not_called()
131+
132+
m_connected_ports_boards.assert_called_once()
133+
m_ask_missing_params.assert_called_once()
134+
135+
if serialports:
136+
assert result.exit_code == 0
137+
else:
138+
assert result.exit_code == 1
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from pathlib import Path
2+
from typing import List
3+
4+
import pytest
5+
from click.testing import CliRunner
6+
from mock import Mock
7+
from pytest_mock import MockerFixture
8+
9+
# # module under test :
10+
from mpflash import cli_main
11+
from mpflash.ask_input import DownloadParams
12+
from mpflash.mpremoteboard import MPRemoteBoard
13+
14+
# mark all tests
15+
pytestmark = pytest.mark.mpflash
16+
17+
18+
##########################################################################################
19+
# list
20+
21+
22+
@pytest.mark.parametrize(
23+
"id, ex_code, args",
24+
[
25+
("1", 0, ["list"]),
26+
("2", 0, ["list", "--json"]),
27+
("3", 0, ["list", "--no-progress"]),
28+
("4", 0, ["list", "--json", "--no-progress"]),
29+
],
30+
)
31+
def test_mpflash_list(id, ex_code, args: List[str], mocker: MockerFixture):
32+
33+
m_list_mcus = mocker.patch("mpflash.cli_list.list_mcus", return_value=[], autospec=True)
34+
m_show_mcus = mocker.patch("mpflash.cli_list.show_mcus", return_value=None, autospec=True)
35+
m_print = mocker.patch("mpflash.cli_list.print", return_value=None, autospec=True)
36+
37+
runner = CliRunner()
38+
result = runner.invoke(cli_main.cli, args)
39+
assert result.exit_code == ex_code
40+
41+
m_list_mcus.assert_called_once()
42+
if "--json" in args:
43+
m_print.assert_called_once()
44+
if "--no-progress" not in args and "--json" not in args:
45+
m_show_mcus.assert_called_once()
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from pathlib import Path
2+
from typing import List
3+
4+
import pytest
5+
from click.testing import CliRunner
6+
from pytest_mock import MockerFixture
7+
8+
# module under test :
9+
import mpflash.cli_group as cli_group
10+
import mpflash.cli_main as cli_main
11+
12+
# mark all tests
13+
pytestmark = [pytest.mark.mpflash, pytest.mark.cli]
14+
15+
16+
##########################################################################################
17+
# --help
18+
19+
20+
def test_mpflash_help():
21+
# check basic command line sanity check
22+
runner = CliRunner()
23+
result = runner.invoke(cli_main.cli, ["--help"])
24+
assert result.exit_code == 0
25+
expected = ["Usage:", "Options", "Commands", "download", "flash", "list"]
26+
for word in expected:
27+
assert word in result.output
28+
29+
30+
# def test_cli_verbose():
31+
# # can turn on verbose mode
32+
# runner = CliRunner()
33+
# result = runner.invoke(cli_main.cli, ["--verbose"])
34+
# assert cli_group.config.verbose == True
35+
36+
37+
def test_cli_ignore():
38+
# can turn on verbose mode
39+
runner = CliRunner()
40+
result = runner.invoke(cli_main.cli, ["--ignore", "COM1", "--ignore", "COM2"])
41+
assert cli_group.config.ignore_ports == ["COM1", "COM2"]
42+
43+
44+
@pytest.mark.parametrize(
45+
"params",
46+
[
47+
["-q"],
48+
["--quiet"],
49+
["-q", "--verbose"],
50+
["--quiet", "--verbose"],
51+
],
52+
)
53+
def test_cli_quiet(params: List[str]):
54+
# can turn on verbose mode
55+
runner = CliRunner()
56+
result = runner.invoke(cli_main.cli, params)
57+
assert cli_group.config.quiet == True
58+
assert cli_group.config.verbose == False

0 commit comments

Comments
 (0)