1# Copyright (c) 2018 Foundries.io
2# Copyright (c) 2020 Nordic Semiconductor ASA
3#
4# SPDX-License-Identifier: Apache-2.0
5
6import argparse
7import functools
8import io
9import os
10import shlex
11import typing
12from unittest.mock import patch, call
13
14import pytest
15
16from runners.nrfjprog import NrfJprogBinaryRunner
17from runners.nrfutil import NrfUtilBinaryRunner
18from conftest import RC_KERNEL_HEX
19
20
21#
22# Test values
23#
24
25TEST_DEF_SNR = 'test-default-serial-number'  # for mocking user input
26TEST_OVR_SNR = 'test-override-serial-number'
27
28TEST_TOOL_OPT = '--ip 192.168.1.10'
29TEST_TOOL_OPT_L = shlex.split(TEST_TOOL_OPT)
30
31CLASS_MAP = {'nrfjprog': NrfJprogBinaryRunner, 'nrfutil': NrfUtilBinaryRunner}
32
33#
34# A dictionary mapping test cases to expected results.
35#
36# The keys are TC objects.
37#
38# The values are usually tool commands we expect to be executed for
39# each test case. Verification is done by mocking the check_call()
40# ZephyrBinaryRunner method which is used to run the commands.
41#
42# Values can also be callables which take a tmpdir and return the
43# expected commands. This is needed for nRF53 testing.
44#
45
46class TC(typing.NamedTuple):    # 'TestCase'
47    # NRF51, NRF52, etc.
48    family: str
49
50    # 'APP', 'NET', 'APP+NET', or None.
51    coprocessor: typing.Optional[str]
52
53    # Run a recover command first if True
54    recover: bool
55
56    # Use --reset instead of --pinreset if True
57    softreset: bool
58
59    # Use --pinreset instead of --reset if True
60    pinreset: bool
61
62    # --snr TEST_OVR_SNR if True, --snr TEST_DEF_SNR if False
63    snr: bool
64
65    # --chiperase if True,
66    # --sectorerase if False (or --sectoranduicrerase on nRF52)
67    erase: bool
68
69    # --tool-opt TEST_TOOL_OPT if True
70    tool_opt: bool
71
72EXPECTED_MAP = {'nrfjprog': 0, 'nrfutil': 1}
73EXPECTED_RESULTS = {
74
75    # -------------------------------------------------------------------------
76    # NRF51
77    #
78    #  family   CP    recov  soft   pin    snr    erase  tool_opt
79    TC('nrf51', None, False, False, False, False, False, False):
80    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51',
81      '--snr', TEST_DEF_SNR],
82     ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
83     (TEST_DEF_SNR, None)),
84
85    TC('nrf51', None, False, False, False, False, True, False):
86    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51',
87      '--snr', TEST_DEF_SNR],
88     ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
89     (TEST_DEF_SNR, None)),
90
91    TC('nrf51', None, False, False, True, True, False, False):
92    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51',
93      '--snr', TEST_OVR_SNR],
94     ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
95     (TEST_OVR_SNR, None)),
96
97    TC('nrf51', None, False, True, False, False, False, False):
98    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51',
99      '--snr', TEST_DEF_SNR],
100     ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
101     (TEST_DEF_SNR, None)),
102
103    TC('nrf51', None, True, False, True, False, False, False):
104    ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
105     ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51',
106      '--snr', TEST_DEF_SNR],
107     ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
108     (TEST_DEF_SNR, None)),
109
110    TC('nrf51', None, True, True, False, True, True, False):
111    ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
112     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51',
113      '--snr', TEST_OVR_SNR],
114     ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
115     (TEST_OVR_SNR, None)),
116
117    TC('nrf51', None, True, True, False, True, True, True):
118    ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
119     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51',
120      '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
121     ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L),
122     (TEST_OVR_SNR, None)),
123
124    # -------------------------------------------------------------------------
125    # NRF52
126    #
127    #  family   CP    recov  soft   pin    snr    erase  tool_opt
128    TC('nrf52', None, False, False, False, False, False, False):
129    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
130      '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
131     ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
132     (TEST_DEF_SNR, None)),
133
134    TC('nrf52', None, False, False, True, False, True, False):
135    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52',
136      '--snr', TEST_DEF_SNR],
137     ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
138     ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
139     (TEST_DEF_SNR, None)),
140
141    TC('nrf52', None, False, False, False, True, False, False):
142    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
143      '--verify', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
144     ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
145     (TEST_OVR_SNR, None)),
146
147    TC('nrf52', None, False, True, False, False, False, False):
148    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
149      '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
150     ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
151     (TEST_DEF_SNR, None)),
152
153    TC('nrf52', None, True, False, True, False, False, False):
154    ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
155     ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
156      '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
157     ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
158     ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
159     (TEST_DEF_SNR, None)),
160
161    TC('nrf52', None, True, True, False, True, True, False):
162    ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
163     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52',
164      '--snr', TEST_OVR_SNR],
165     ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
166     (TEST_OVR_SNR, None)),
167
168    TC('nrf52', None, True, True, False, True, True, True):
169    ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
170     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52',
171      '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
172     ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L),
173     (TEST_OVR_SNR, None)),
174
175    # -------------------------------------------------------------------------
176    # NRF53 APP
177    #
178    #  family   CP     recov  soft   pin    snr    erase  tool_opt
179    TC('nrf53', 'APP', False, False, False, False, False, False):
180    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
181      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR],
182     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
183     (TEST_DEF_SNR, None)),
184
185    TC('nrf53', 'APP', False, False, True, False, True, False):
186    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase',
187      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR],
188     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
189     (TEST_DEF_SNR, None)),
190
191    TC('nrf53', 'APP', False, False, False, True, False, False):
192    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
193      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR],
194     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
195     (TEST_OVR_SNR, None)),
196
197    TC('nrf53', 'APP', False, True, False, False, False, False):
198    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
199      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR],
200     ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
201     (TEST_DEF_SNR, None)),
202
203    TC('nrf53', 'APP', True, False, True, False, False, False):
204    ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
205      '--snr', TEST_DEF_SNR],
206     ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
207     ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
208      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR],
209     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
210     (TEST_DEF_SNR, None)),
211
212    TC('nrf53', 'APP', True, True, False, True, True, False):
213    ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
214      '--snr', TEST_OVR_SNR],
215     ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
216     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase',
217      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR],
218     ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
219     (TEST_OVR_SNR, None)),
220
221    # -------------------------------------------------------------------------
222    # NRF53 NET
223    #
224    #  family   CP     recov  soft   pin    snr    erase  tool_opt
225    TC('nrf53', 'NET', False, False, False, False, False, False):
226    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
227      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR],
228     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
229     (TEST_DEF_SNR, None)),
230
231    TC('nrf53', 'NET', False, False, True, False, True, False):
232    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase',
233      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR],
234     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
235     (TEST_DEF_SNR, None)),
236
237    TC('nrf53', 'NET', False, False, False, True, False, False):
238    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
239      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR],
240     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
241     (TEST_OVR_SNR, None)),
242
243    TC('nrf53', 'NET', False, True, False, False, False, False):
244    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
245      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR],
246     ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
247     (TEST_DEF_SNR, None)),
248
249    TC('nrf53', 'NET', True, False, True, False, False, False):
250    ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
251      '--snr', TEST_DEF_SNR],
252     ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
253     ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase',
254      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR],
255     ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
256     (TEST_DEF_SNR, None)),
257
258    TC('nrf53', 'NET', True, True, False, True, True, False):
259    ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
260      '--snr', TEST_OVR_SNR],
261     ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
262     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase',
263      '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR],
264     ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
265     (TEST_OVR_SNR, None)),
266
267    # -------------------------------------------------------------------------
268    # NRF91
269    #
270    #  family   CP    recov  soft   pin    snr    erase  tool_opt
271    TC('nrf91', None, False, False, False, False, False, False):
272    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91',
273      '--snr', TEST_DEF_SNR],
274     ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
275     (TEST_DEF_SNR, None)),
276
277    TC('nrf91', None, False, False, True, False, True, False):
278    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91',
279      '--snr', TEST_DEF_SNR],
280     ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
281     (TEST_DEF_SNR, None)),
282
283    TC('nrf91', None, False, False, False, True, False, False):
284    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91',
285      '--snr', TEST_OVR_SNR],
286     ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
287     (TEST_OVR_SNR, None)),
288
289    TC('nrf91', None, False, True, False, False, False, False):
290    ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91',
291      '--snr', TEST_DEF_SNR],
292     ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
293     (TEST_DEF_SNR, None)),
294
295    TC('nrf91', None, True, False, True, False, False, False):
296    ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
297     ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91',
298      '--snr', TEST_DEF_SNR],
299     ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
300     (TEST_DEF_SNR, None)),
301
302    TC('nrf91', None, True, True, False, True, True, False):
303    ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
304     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91',
305      '--snr', TEST_OVR_SNR],
306     ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
307     (TEST_OVR_SNR, None)),
308
309    TC('nrf91', None, True, True, False, True, True, True):
310    ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
311     ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91',
312      '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L,
313     ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L),
314     (TEST_OVR_SNR, None)),
315}
316
317#
318# Monkey-patches
319#
320
321def get_board_snr_patch(glob):
322    return TEST_DEF_SNR
323
324def require_patch(cur_tool, program):
325    assert cur_tool == program
326
327os_path_isfile = os.path.isfile
328
329def os_path_isfile_patch(filename):
330    if filename == RC_KERNEL_HEX:
331        return True
332    return os_path_isfile(filename)
333
334#
335# Test functions.
336#
337# These are white box tests that rely on the above monkey-patches.
338#
339
340def id_fn(test_case):
341    if test_case.coprocessor is None:
342        cp = ''
343    else:
344        cp = f'-{test_case.coprocessor}'
345    s = 'soft_reset' if test_case.softreset else 'no_soft_reset'
346    p = 'pin_reset' if test_case.pinreset else 'no_pin_reset'
347    sn = 'default_snr' if test_case.snr else 'override_snr'
348    e = 'chip_erase' if test_case.erase else 'sector[anduicr]_erase'
349    r = 'recover' if test_case.recover else 'no_recover'
350    t = 'tool_opt' if test_case.tool_opt else 'no_tool_opt'
351
352    return f'{test_case.family[:5]}{cp}-{s}-{p}-{sn}-{e}-{r}-{t}'
353
354def fix_up_runner_config(test_case, runner_config, tmpdir):
355    # Helper that adjusts the common runner_config fixture for our
356    # nRF-specific tests.
357
358    to_replace = {}
359
360    # Provide a skeletal zephyr/.config file to use as the runner's
361    # BuildConfiguration.
362    zephyr = tmpdir / 'zephyr'
363    zephyr.mkdir()
364    dotconfig = os.fspath(zephyr / '.config')
365    with open(dotconfig, 'w') as f:
366        f.write(f'''
367CONFIG_SOC_SERIES_{test_case.family.upper()}X=y
368''')
369        if test_case.family == 'nrf53':
370            f.write(f'''
371CONFIG_SOC_NRF5340_CPU{test_case.coprocessor}=y
372''')
373
374    to_replace['build_dir'] = tmpdir
375
376    return runner_config._replace(**to_replace)
377
378def check_expected(tool, test_case, check_fn, get_snr, tmpdir, runner_config):
379
380    expected = EXPECTED_RESULTS[test_case][EXPECTED_MAP[tool]]
381    if tool == 'nrfutil':
382        # Skip the preparation calls for now
383        assert len(check_fn.call_args_list) >= 1
384        xi = len(check_fn.call_args_list) - 1
385        assert len(check_fn.call_args_list[xi].args) == 1
386        # Extract filename
387        nrfutil_args = check_fn.call_args_list[xi].args[0]
388        tmpfile = nrfutil_args[nrfutil_args.index('--batch-path') + 1]
389        cmds = (['nrfutil', '--json', 'device', 'x-execute-batch', '--batch-path',
390                 tmpfile, '--serial-number', expected[0]],)
391        call_args = [call(nrfutil_args)]
392    else:
393        cmds = expected
394        call_args = check_fn.call_args_list
395
396    if callable(cmds):
397        assert (call_args ==
398                [call(x) for x in cmds(tmpdir, runner_config.hex_file)])
399    else:
400        assert call_args == [call(x) for x in cmds]
401
402    if not test_case.snr:
403        get_snr.assert_called_once_with('*')
404    else:
405        get_snr.assert_not_called()
406
407@pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"])
408@pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn)
409@patch('runners.core.ZephyrBinaryRunner.require')
410@patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr',
411       side_effect=get_board_snr_patch)
412@patch('runners.nrfutil.subprocess.Popen')
413@patch('runners.nrfjprog.NrfBinaryRunner.check_call')
414def test_init(check_call, popen, get_snr, require, tool, test_case,
415              runner_config, tmpdir):
416    popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'')
417    popen.return_value.__enter__.return_value.returncode = 0
418
419    require.side_effect = functools.partial(require_patch, tool)
420    runner_config = fix_up_runner_config(test_case, runner_config, tmpdir)
421    snr = TEST_OVR_SNR if test_case.snr else None
422    tool_opt = TEST_TOOL_OPT_L if test_case.tool_opt else []
423    cls = CLASS_MAP[tool]
424    runner = cls(runner_config,
425                 test_case.family,
426                 test_case.softreset,
427                 test_case.pinreset,
428                 snr,
429                 erase=test_case.erase,
430                 tool_opt=tool_opt,
431                 recover=test_case.recover)
432
433    with patch('os.path.isfile', side_effect=os_path_isfile_patch):
434        runner.run('flash')
435    assert require.called
436
437    CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen}
438    check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir,
439                   runner_config)
440
441@pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"])
442@pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn)
443@patch('runners.core.ZephyrBinaryRunner.require')
444@patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr',
445       side_effect=get_board_snr_patch)
446@patch('runners.nrfutil.subprocess.Popen')
447@patch('runners.nrfjprog.NrfBinaryRunner.check_call')
448def test_create(check_call, popen, get_snr, require, tool, test_case,
449                runner_config, tmpdir):
450    popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'')
451    popen.return_value.__enter__.return_value.returncode = 0
452
453    require.side_effect = functools.partial(require_patch, tool)
454    runner_config = fix_up_runner_config(test_case, runner_config, tmpdir)
455
456    args = []
457    if test_case.softreset:
458        args.append('--softreset')
459    if test_case.pinreset:
460        args.append('--pinreset')
461    if test_case.snr:
462        args.extend(['--dev-id', TEST_OVR_SNR])
463    if test_case.erase:
464        args.append('--erase')
465    if test_case.recover:
466        args.append('--recover')
467    if test_case.tool_opt:
468        args.extend(['--tool-opt', TEST_TOOL_OPT])
469
470    parser = argparse.ArgumentParser(allow_abbrev=False)
471    cls = CLASS_MAP[tool]
472    cls.add_parser(parser)
473    arg_namespace = parser.parse_args(args)
474    runner = cls.create(runner_config, arg_namespace)
475    with patch('os.path.isfile', side_effect=os_path_isfile_patch):
476        runner.run('flash')
477
478    assert require.called
479
480    CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen}
481    check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir,
482                   runner_config)
483