a101d1f604a3ad6de242989f7a4887b78ab012a1
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

1) # SPDX-FileCopyrightText: 2024 Marco Ricci <m@the13thletter.info>
2) #
3) # SPDX-License-Identifier: MIT
4) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

5) from __future__ import annotations
6) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

7) import contextlib
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

8) import json
9) import os
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

10) import socket
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

11) from typing import TYPE_CHECKING, cast
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

12) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

13) import click.testing
14) import pytest
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

15) from typing_extensions import NamedTuple
16) 
17) import derivepassphrase as dpp
18) import ssh_agent_client
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

19) import tests
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

20) from derivepassphrase import cli
21) 
22) if TYPE_CHECKING:
23)     from collections.abc import Callable
24) 
25)     from typing_extensions import Any
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

26) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

27) DUMMY_SERVICE = tests.DUMMY_SERVICE
28) DUMMY_PASSPHRASE = tests.DUMMY_PASSPHRASE
29) DUMMY_CONFIG_SETTINGS = tests.DUMMY_CONFIG_SETTINGS
30) DUMMY_RESULT_PASSPHRASE = tests.DUMMY_RESULT_PASSPHRASE
31) DUMMY_RESULT_KEY1 = tests.DUMMY_RESULT_KEY1
32) DUMMY_PHRASE_FROM_KEY1_RAW = tests.DUMMY_PHRASE_FROM_KEY1_RAW
33) DUMMY_PHRASE_FROM_KEY1 = tests.DUMMY_PHRASE_FROM_KEY1
34) 
35) DUMMY_KEY1 = tests.DUMMY_KEY1
36) DUMMY_KEY1_B64 = tests.DUMMY_KEY1_B64
37) DUMMY_KEY2 = tests.DUMMY_KEY2
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

38) 
39) 
40) class IncompatibleConfiguration(NamedTuple):
41)     other_options: list[tuple[str, ...]]
42)     needs_service: bool | None
43)     input: bytes | None
44) 
45) class SingleConfiguration(NamedTuple):
46)     needs_service: bool | None
47)     input: bytes | None
48)     check_success: bool
49) 
50) class OptionCombination(NamedTuple):
51)     options: list[str]
52)     incompatible: bool
53)     needs_service: bool | None
54)     input: bytes | None
55)     check_success: bool
56) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

57) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

58) PASSWORD_GENERATION_OPTIONS: list[tuple[str, ...]] = [
59)     ('--phrase',), ('--key',), ('--length', '20'), ('--repeat', '20'),
60)     ('--lower', '1'), ('--upper', '1'), ('--number', '1'),
61)     ('--space', '1'), ('--dash', '1'), ('--symbol', '1')
62) ]
63) CONFIGURATION_OPTIONS: list[tuple[str, ...]] = [
64)     ('--notes',), ('--config',), ('--delete',), ('--delete-globals',),
65)     ('--clear',)
66) ]
67) CONFIGURATION_COMMANDS: list[tuple[str, ...]] = [
68)     ('--notes',), ('--delete',), ('--delete-globals',), ('--clear',)
69) ]
70) STORAGE_OPTIONS: list[tuple[str, ...]] = [
71)     ('--export', '-'), ('--import', '-')
72) ]
73) INCOMPATIBLE: dict[tuple[str, ...], IncompatibleConfiguration] = {
74)     ('--phrase',): IncompatibleConfiguration(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

75)         [('--key',), *CONFIGURATION_COMMANDS, *STORAGE_OPTIONS],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

76)         True, DUMMY_PASSPHRASE),
77)     ('--key',): IncompatibleConfiguration(
78)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
79)         True, DUMMY_PASSPHRASE),
80)     ('--length', '20'): IncompatibleConfiguration(
81)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
82)         True, DUMMY_PASSPHRASE),
83)     ('--repeat', '20'): IncompatibleConfiguration(
84)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
85)         True, DUMMY_PASSPHRASE),
86)     ('--lower', '1'): IncompatibleConfiguration(
87)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
88)         True, DUMMY_PASSPHRASE),
89)     ('--upper', '1'): IncompatibleConfiguration(
90)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
91)         True, DUMMY_PASSPHRASE),
92)     ('--number', '1'): IncompatibleConfiguration(
93)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
94)         True, DUMMY_PASSPHRASE),
95)     ('--space', '1'): IncompatibleConfiguration(
96)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
97)         True, DUMMY_PASSPHRASE),
98)     ('--dash', '1'): IncompatibleConfiguration(
99)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
100)         True, DUMMY_PASSPHRASE),
101)     ('--symbol', '1'): IncompatibleConfiguration(
102)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS,
103)         True, DUMMY_PASSPHRASE),
104)     ('--notes',): IncompatibleConfiguration(
105)         [('--config',), ('--delete',), ('--delete-globals',),
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

106)          ('--clear',), *STORAGE_OPTIONS],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

107)         True, None),
108)     ('--config', '-p'): IncompatibleConfiguration(
109)         [('--delete',), ('--delete-globals',),
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

110)          ('--clear',), *STORAGE_OPTIONS],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

111)         None, DUMMY_PASSPHRASE),
112)     ('--delete',): IncompatibleConfiguration(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

113)         [('--delete-globals',), ('--clear',), *STORAGE_OPTIONS], True, None),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

114)     ('--delete-globals',): IncompatibleConfiguration(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

115)         [('--clear',), *STORAGE_OPTIONS], False, None),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

116)     ('--clear',): IncompatibleConfiguration(STORAGE_OPTIONS, False, None),
117)     ('--export', '-'): IncompatibleConfiguration(
118)         [('--import', '-')], False, None),
119)     ('--import', '-'): IncompatibleConfiguration(
120)         [], False, None),
121) }
122) SINGLES: dict[tuple[str, ...], SingleConfiguration] = {
123)     ('--phrase',): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
124)     ('--key',): SingleConfiguration(True, None, False),
125)     ('--length', '20'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
126)     ('--repeat', '20'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
127)     ('--lower', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
128)     ('--upper', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
129)     ('--number', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
130)     ('--space', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
131)     ('--dash', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
132)     ('--symbol', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
133)     ('--notes',): SingleConfiguration(True, None, False),
134)     ('--config', '-p'): SingleConfiguration(None, DUMMY_PASSPHRASE, False),
135)     ('--delete',): SingleConfiguration(True, None, False),
136)     ('--delete-globals',): SingleConfiguration(False, None, True),
137)     ('--clear',): SingleConfiguration(False, None, True),
138)     ('--export', '-'): SingleConfiguration(False, None, True),
139)     ('--import', '-'): SingleConfiguration(False, b'{"services": {}}', True),
140) }
141) INTERESTING_OPTION_COMBINATIONS: list[OptionCombination] = []
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

142) config: IncompatibleConfiguration | SingleConfiguration
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

143) for opt, config in INCOMPATIBLE.items():
144)     for opt2 in config.other_options:
145)         INTERESTING_OPTION_COMBINATIONS.extend([
146)             OptionCombination(options=list(opt + opt2), incompatible=True,
147)                               needs_service=config.needs_service,
148)                               input=config.input, check_success=False),
149)             OptionCombination(options=list(opt2 + opt), incompatible=True,
150)                               needs_service=config.needs_service,
151)                               input=config.input, check_success=False)
152)         ])
153) for opt, config in SINGLES.items():
154)     INTERESTING_OPTION_COMBINATIONS.append(
155)         OptionCombination(options=list(opt), incompatible=False,
156)                           needs_service=config.needs_service,
157)                           input=config.input,
158)                           check_success=config.check_success))
159) 
160) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

161) class TestCLI:
162)     def test_200_help_output(self):
163)         runner = click.testing.CliRunner(mix_stderr=False)
164)         result = runner.invoke(cli.derivepassphrase, ['--help'],
165)                                catch_exceptions=False)
166)         assert result.exit_code == 0
167)         assert 'Password generation:\n' in result.output, (
168)             'Option groups not respected in help text.'
169)         )
170)         assert 'Use NUMBER=0, e.g. "--symbol 0"' in result.output, (
171)             'Option group epilog not printed.'
172)         )
173) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

174)     @pytest.mark.parametrize('charset_name',
175)                              ['lower', 'upper', 'number', 'space',
176)                               'dash', 'symbol'])
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

177)     def test_201_disable_character_set(
178)         self, monkeypatch: Any, charset_name: str
179)     ) -> None:
180)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
181)         option = f'--{charset_name}'
182)         charset = dpp.Vault._CHARSETS[charset_name].decode('ascii')
183)         runner = click.testing.CliRunner(mix_stderr=False)
184)         result = runner.invoke(cli.derivepassphrase,
185)                                [option, '0', '-p', DUMMY_SERVICE],
186)                                input=DUMMY_PASSPHRASE, catch_exceptions=False)
187)         assert result.exit_code == 0, (
188)             f'program died unexpectedly with exit code {result.exit_code}'
189)         )
190)         assert not result.stderr_bytes, (
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

191)             f'program barfed on stderr: {result.stderr_bytes!r}'
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

192)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

193)         for c in charset:
194)             assert c not in result.stdout, (
195)                 f'derived password contains forbidden character {c!r}: '
196)                 f'{result.stdout!r}'
197)             )
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

198) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

199)     def test_202_disable_repetition(self, monkeypatch: Any) -> None:
200)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
201)         runner = click.testing.CliRunner(mix_stderr=False)
202)         result = runner.invoke(cli.derivepassphrase,
203)                                ['--repeat', '0', '-p', DUMMY_SERVICE],
204)                                input=DUMMY_PASSPHRASE, catch_exceptions=False)
205)         assert result.exit_code == 0, (
206)             f'program died unexpectedly with exit code {result.exit_code}'
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

207)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

208)         assert not result.stderr_bytes, (
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

209)             f'program barfed on stderr: {result.stderr_bytes!r}'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

210)         )
211)         passphrase = result.stdout.rstrip('\r\n')
212)         for i in range(len(passphrase) - 1):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

213)             assert passphrase[i:i + 1] != passphrase[i + 1:i + 2], (
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

214)                 f'derived password contains repeated character '
215)                 f'at position {i}: {result.stdout!r}'
216)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

217) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

218)     @pytest.mark.parametrize('config', [
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

219)         pytest.param({'global': {'key': DUMMY_KEY1_B64},
220)                       'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
221)                      id='global'),
222)         pytest.param({'global': {'phrase': DUMMY_PASSPHRASE.rstrip(b'\n')
223)                                            .decode('ASCII')},
224)                       'services': {DUMMY_SERVICE: {'key': DUMMY_KEY1_B64,
225)                                                    **DUMMY_CONFIG_SETTINGS}}},
226)                      id='service'),
227)     ])
228)     def test_204a_key_from_config(
229)         self, monkeypatch: Any, config: dpp.types.VaultConfig,
230)     ) -> None:
231)         runner = click.testing.CliRunner(mix_stderr=False)
232)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
233)                                    config=config):
234)             monkeypatch.setattr(dpp.Vault, 'phrase_from_key',
235)                                 tests.phrase_from_key)
236)             result = runner.invoke(cli.derivepassphrase, [DUMMY_SERVICE],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

237)                                    catch_exceptions=False)
238)             assert (result.exit_code, result.stderr_bytes) == (0, b''), (
239)                 'program exited with failure'
240)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

241)             assert (
242)                 result.stdout_bytes.rstrip(b'\n') != DUMMY_RESULT_PASSPHRASE
243)             ), (
244)                 'program generated unexpected result (phrase instead of key)'
245)             )
246)             assert result.stdout_bytes.rstrip(b'\n') == DUMMY_RESULT_KEY1, (
247)                 'program generated unexpected result (wrong settings?)'
248)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

249) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

250)     def test_204b_key_from_command_line(self, monkeypatch: Any) -> None:
251)         runner = click.testing.CliRunner(mix_stderr=False)
252)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
253)                                    config={'services': {DUMMY_SERVICE:
254)                                                DUMMY_CONFIG_SETTINGS}}):
255)             monkeypatch.setattr(cli, '_get_suitable_ssh_keys',
256)                                 tests.suitable_ssh_keys)
257)             monkeypatch.setattr(dpp.Vault, 'phrase_from_key',
258)                                 tests.phrase_from_key)
259)             result = runner.invoke(cli.derivepassphrase,
260)                                    ['-k', DUMMY_SERVICE],
261)                                    input=b'1\n', catch_exceptions=False)
262)             assert result.exit_code == 0, 'program exited with failure'
263)             assert result.stdout_bytes, 'program output expected'
264)             last_line = result.stdout_bytes.splitlines(True)[-1]
265)             assert last_line.rstrip(b'\n') != DUMMY_RESULT_PASSPHRASE, (
266)                 'program generated unexpected result (phrase instead of key)'
267)             )
268)             assert last_line.rstrip(b'\n') == DUMMY_RESULT_KEY1, (
269)                 'program generated unexpected result (wrong settings?)'
270)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

271) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

272)     def test_205_service_phrase_if_key_in_global_config(
273)         self, monkeypatch: Any,
274)     ) -> None:
275)         runner = click.testing.CliRunner(mix_stderr=False)
276)         with tests.isolated_config(
277)             monkeypatch=monkeypatch, runner=runner,
278)             config={
279)                 'global': {'key': DUMMY_KEY1_B64},
280)                 'services': {
281)                     DUMMY_SERVICE: {
282)                         'phrase': DUMMY_PASSPHRASE.rstrip(b'\n')
283)                                   .decode('ASCII'),
284)                         **DUMMY_CONFIG_SETTINGS}}}
285)         ):
286)             result = runner.invoke(cli.derivepassphrase, [DUMMY_SERVICE],
287)                                    catch_exceptions=False)
288)             assert result.exit_code == 0, 'program exited with failure'
289)             assert result.stdout_bytes, 'program output expected'
290)             last_line = result.stdout_bytes.splitlines(True)[-1]
291)             assert last_line.rstrip(b'\n') != DUMMY_RESULT_KEY1, (
292)                 'program generated unexpected result (key instead of phrase)'
293)             )
294)             assert last_line.rstrip(b'\n') == DUMMY_RESULT_PASSPHRASE, (
295)                 'program generated unexpected result (wrong settings?)'
296)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

297) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

298)     @pytest.mark.parametrize('option',
299)                              ['--lower', '--upper', '--number',
300)                               '--space', '--dash', '--symbol',
301)                               '--repeat', '--length'])
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

302)     def test_210_invalid_argument_range(self, option: str) -> None:
303)         runner = click.testing.CliRunner(mix_stderr=False)
304)         value: str | int
305)         for value in '-42', 'invalid':
306)             result = runner.invoke(cli.derivepassphrase,
307)                                    [option, cast(str, value), '-p',
308)                                     DUMMY_SERVICE],
309)                                    input=DUMMY_PASSPHRASE,
310)                                    catch_exceptions=False)
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

311)             assert result.exit_code > 0, (
312)                 'program unexpectedly succeeded'
313)             )
314)             assert result.stderr_bytes, (
315)                 'program did not print any error message'
316)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

317)             assert b'Error: Invalid value' in result.stderr_bytes, (
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

318)                 'program did not print the expected error message'
319)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

320) 
321)     @pytest.mark.parametrize(
322)         ['options', 'service', 'input', 'check_success'],
323)         [(o.options, o.needs_service, o.input, o.check_success)
324)          for o in INTERESTING_OPTION_COMBINATIONS if not o.incompatible],
325)     )
326)     def test_211_service_needed(
327)         self, monkeypatch: Any, options: list[str],
328)         service: bool | None, input: bytes | None, check_success: bool,
329)     ) -> None:
330)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
331)         runner = click.testing.CliRunner(mix_stderr=False)
332)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
333)                                    config={'global': {'phrase': 'abc'},
334)                                            'services': {}}):
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

335)             result = runner.invoke(cli.derivepassphrase,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

336)                                    options if service
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

337)                                    else [*options, DUMMY_SERVICE],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

338)                                    input=input, catch_exceptions=False)
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

339)             if service is not None:
340)                 assert result.exit_code > 0, (
341)                     'program unexpectedly succeeded'
342)                 )
343)                 assert result.stderr_bytes, (
344)                     'program did not print any error message'
345)                 )
346)                 err_msg = (b' requires a SERVICE' if service
347)                            else b' does not take a SERVICE argument')
348)                 assert err_msg in result.stderr_bytes, (
349)                     'program did not print the expected error message'
350)                 )
351)             else:
352)                 assert (result.exit_code, result.stderr_bytes) == (0, b''), (
353)                     'program unexpectedly failed'
354)                 )
355)         if check_success:
356)             with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
357)                                        config={'global': {'phrase': 'abc'},
358)                                                'services': {}}):
359)                 monkeypatch.setattr(cli, '_prompt_for_passphrase',
360)                                     tests.auto_prompt)
361)                 result = runner.invoke(cli.derivepassphrase,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

362)                                        [*options, DUMMY_SERVICE]
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

363)                                        if service else options,
364)                                        input=input, catch_exceptions=False)
365)                 assert (result.exit_code, result.stderr_bytes) == (0, b''), (
366)                     'program unexpectedly failed'
367)                 )
368) 
369)     @pytest.mark.parametrize(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

370)         ['options', 'service'],
371)         [(o.options, o.needs_service)
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

372)          for o in INTERESTING_OPTION_COMBINATIONS if o.incompatible],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

373)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

374)     def test_212_incompatible_options(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

375)         self, options: list[str], service: bool | None,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

376)     ) -> None:
377)         runner = click.testing.CliRunner(mix_stderr=False)
378)         result = runner.invoke(cli.derivepassphrase,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

379)                                [*options, DUMMY_SERVICE] if service
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

380)                                else options,
381)                                input=DUMMY_PASSPHRASE, catch_exceptions=False)
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

382)         assert result.exit_code > 0, (
383)             'program unexpectedly succeeded'
384)         )
385)         assert result.stderr_bytes, (
386)             'program did not print any error message'
387)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

388)         assert b'mutually exclusive with ' in result.stderr_bytes, (
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

389)             'program did not print the expected error message'
390)         )
391) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

392)     def test_213_import_bad_config_not_vault_config(
393)         self, monkeypatch: Any,
394)     ) -> None:
395)         runner = click.testing.CliRunner(mix_stderr=False)
396)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
397)                                    config={'services': {}}):
398)             result = runner.invoke(cli.derivepassphrase, ['--import', '-'],
399)                                    input=b'null', catch_exceptions=False)
400)             assert result.exit_code > 0, (
401)                 'program unexpectedly succeeded'
402)             )
403)             assert result.stderr_bytes, (
404)                 'program did not print any error message'
405)             )
406)             assert b'not a valid config' in result.stderr_bytes, (
407)                 'program did not print the expected error message'
408)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

409) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

410)     def test_213a_import_bad_config_not_json_data(
411)         self, monkeypatch: Any,
412)     ) -> None:
413)         runner = click.testing.CliRunner(mix_stderr=False)
414)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
415)                                    config={'services': {}}):
416)             result = runner.invoke(cli.derivepassphrase, ['--import', '-'],
417)                                    input=b'This string is not valid JSON.',
418)                                    catch_exceptions=False)
419)             assert result.exit_code > 0, (
420)                 'program unexpectedly succeeded'
421)             )
422)             assert result.stderr_bytes, (
423)                 'program did not print any error message'
424)             )
425)             assert b'cannot decode JSON' in result.stderr_bytes, (
426)                 'program did not print the expected error message'
427)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

428) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

429)     def test_213b_import_bad_config_not_a_file(
430)         self, monkeypatch: Any,
431)     ) -> None:
432)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

433)         # `isolated_config` validates the configuration.  So, to pass an
434)         # actual broken configuration, we must open the configuration file
435)         # ourselves afterwards, inside the context.
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

436)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
437)                                    config={'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

438)             with open(cli._config_filename(), 'w',
439)                       encoding='UTF-8') as outfile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

440)                 print('This string is not valid JSON.', file=outfile)
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

441)             dname = os.path.dirname(cli._config_filename())
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

442)             result = runner.invoke(
443)                 cli.derivepassphrase,
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

444)                 ['--import', os.fsdecode(dname)],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

445)                 catch_exceptions=False)
446)             assert result.exit_code > 0, (
447)                 'program unexpectedly succeeded'
448)             )
449)             assert result.stderr_bytes, (
450)                 'program did not print any error message'
451)             )
452)             # Don't test the actual error message, because it is subject to
453)             # locale settings.  TODO: find a way anyway.
454) 
455)     def test_214_export_settings_no_stored_settings(
456)         self, monkeypatch: Any,
457)     ) -> None:
458)         runner = click.testing.CliRunner(mix_stderr=False)
459)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
460)                                    config={'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

461)             with contextlib.suppress(FileNotFoundError):
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

462)                 os.remove(cli._config_filename())
463)             result = runner.invoke(cli.derivepassphrase, ['--export', '-'],
464)                                    catch_exceptions=False)
465)             assert (result.exit_code, result.stderr_bytes) == (0, b''), (
466)                 'program exited with failure'
467)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

468) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

469)     def test_214a_export_settings_bad_stored_config(
470)         self, monkeypatch: Any,
471)     ) -> None:
472)         runner = click.testing.CliRunner(mix_stderr=False)
473)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
474)                                    config={}):
475)             result = runner.invoke(cli.derivepassphrase, ['--export', '-'],
476)                                    input=b'null', catch_exceptions=False)
477)             assert result.exit_code > 0, (
478)                 'program unexpectedly succeeded'
479)             )
480)             assert result.stderr_bytes, (
481)                 'program did not print any error message'
482)             )
483)             assert b'cannot load config' in result.stderr_bytes, (
484)                 'program did not print the expected error message'
485)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

486) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

487)     def test_214b_export_settings_not_a_file(
488)         self, monkeypatch: Any,
489)     ) -> None:
490)         runner = click.testing.CliRunner(mix_stderr=False)
491)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
492)                                    config={'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

493)             with contextlib.suppress(FileNotFoundError):
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

494)                 os.remove(cli._config_filename())
495)             os.makedirs(cli._config_filename())
496)             result = runner.invoke(cli.derivepassphrase, ['--export', '-'],
497)                                    input=b'null', catch_exceptions=False)
498)             assert result.exit_code > 0, (
499)                 'program unexpectedly succeeded'
500)             )
501)             assert result.stderr_bytes, (
502)                 'program did not print any error message'
503)             )
504)             assert b'cannot load config' in result.stderr_bytes, (
505)                 'program did not print the expected error message'
506)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

507) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

508)     def test_214c_export_settings_target_not_a_file(
509)         self, monkeypatch: Any,
510)     ) -> None:
511)         runner = click.testing.CliRunner(mix_stderr=False)
512)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
513)                                    config={'services': {}}):
514)             dname = os.path.dirname(cli._config_filename())
515)             result = runner.invoke(cli.derivepassphrase,
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

516)                                    ['--export', os.fsdecode(dname)],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

517)                                    input=b'null', catch_exceptions=False)
518)             assert result.exit_code > 0, (
519)                 'program unexpectedly succeeded'
520)             )
521)             assert result.stderr_bytes, (
522)                 'program did not print any error message'
523)             )
524)             assert b'cannot write config' in result.stderr_bytes, (
525)                 'program did not print the expected error message'
526)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

527) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

528)     def test_220_edit_notes_successfully(self, monkeypatch: Any) -> None:
529)         edit_result = '''
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

530) 
531) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
532) contents go here
533) '''
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

534)         runner = click.testing.CliRunner(mix_stderr=False)
535)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
536)                                    config={'global': {'phrase': 'abc'},
537)                                            'services': {}}):
538)             monkeypatch.setattr(click, 'edit',
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

539)                                 lambda *a, **kw: edit_result)  # noqa: ARG005
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

540)             result = runner.invoke(cli.derivepassphrase, ['--notes', 'sv'],
541)                                    catch_exceptions=False)
542)             assert (result.exit_code, result.stderr_bytes) == (0, b''), (
543)                 'program exited with failure'
544)             )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

545)             with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

546)                 config = json.load(infile)
547)             assert config == {'global': {'phrase': 'abc'},
548)                               'services': {'sv': {'notes':
549)                                                       'contents go here'}}}
550) 
551)     def test_221_edit_notes_noop(self, monkeypatch: Any) -> None:
552)         runner = click.testing.CliRunner(mix_stderr=False)
553)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
554)                                    config={'global': {'phrase': 'abc'},
555)                                            'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

556)             monkeypatch.setattr(click, 'edit',
557)                                 lambda *a, **kw: None)  # noqa: ARG005
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

558)             result = runner.invoke(cli.derivepassphrase, ['--notes', 'sv'],
559)                                    catch_exceptions=False)
560)             assert (result.exit_code, result.stderr_bytes) == (0, b''), (
561)                 'program exited with failure'
562)             )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

563)             with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

564)                 config = json.load(infile)
565)             assert config == {'global': {'phrase': 'abc'}, 'services': {}}
566) 
567)     def test_222_edit_notes_marker_removed(self, monkeypatch: Any) -> None:
568)         runner = click.testing.CliRunner(mix_stderr=False)
569)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
570)                                    config={'global': {'phrase': 'abc'},
571)                                            'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

572)             monkeypatch.setattr(click, 'edit',
573)                                 lambda *a, **kw: 'long\ntext')  # noqa: ARG005
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

574)             result = runner.invoke(cli.derivepassphrase, ['--notes', 'sv'],
575)                                    catch_exceptions=False)
576)             assert (result.exit_code, result.stderr_bytes) == (0, b''), (
577)                 'program exited with failure'
578)             )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

579)             with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

580)                 config = json.load(infile)
581)             assert config == {'global': {'phrase': 'abc'},
582)                               'services': {'sv': {'notes': 'long\ntext'}}}
583) 
584)     def test_223_edit_notes_abort(self, monkeypatch: Any) -> None:
585)         runner = click.testing.CliRunner(mix_stderr=False)
586)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
587)                                    config={'global': {'phrase': 'abc'},
588)                                            'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

589)             monkeypatch.setattr(click, 'edit',
590)                                 lambda *a, **kw: '\n\n')  # noqa: ARG005
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

591)             result = runner.invoke(cli.derivepassphrase, ['--notes', 'sv'],
592)                                    catch_exceptions=False)
593)             assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

594)             assert result.stderr_bytes is not None
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

595)             assert b'user aborted request' in result.stderr_bytes, (
596)                 'expected error message missing'
597)             )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

598)             with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

599)                 config = json.load(infile)
600)             assert config == {'global': {'phrase': 'abc'}, 'services': {}}
601) 
602)     @pytest.mark.parametrize(['command_line', 'input', 'result_config'], [
603)         (
604)             ['--phrase'],
605)             b'my passphrase\n',
606)             {'global': {'phrase': 'my passphrase'}, 'services': {}},
607)         ),
608)         (
609)             ['--key'],
610)             b'1\n',
611)             {'global': {'key': DUMMY_KEY1_B64}, 'services': {}},
612)         ),
613)         (
614)             ['--phrase', 'sv'],
615)             b'my passphrase\n',
616)             {'global': {'phrase': 'abc'},
617)              'services': {'sv': {'phrase': 'my passphrase'}}},
618)         ),
619)         (
620)             ['--key', 'sv'],
621)             b'1\n',
622)             {'global': {'phrase': 'abc'},
623)              'services': {'sv': {'key': DUMMY_KEY1_B64}}},
624)         ),
625)         (
626)             ['--key', '--length', '15', 'sv'],
627)             b'1\n',
628)             {'global': {'phrase': 'abc'},
629)              'services': {'sv': {'key': DUMMY_KEY1_B64, 'length': 15}}},
630)         ),
631)     ])
632)     def test_224_store_config_good(
633)         self, monkeypatch: Any, command_line: list[str], input: bytes,
634)         result_config: Any,
635)     ) -> None:
636)         runner = click.testing.CliRunner(mix_stderr=False)
637)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
638)                                    config={'global': {'phrase': 'abc'},
639)                                            'services': {}}):
640)             monkeypatch.setattr(cli, '_get_suitable_ssh_keys',
641)                                 tests.suitable_ssh_keys)
642)             result = runner.invoke(cli.derivepassphrase,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

643)                                    ['--config', *command_line],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

644)                                    catch_exceptions=False, input=input)
645)             assert result.exit_code == 0, 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

646)             with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

647)                 config = json.load(infile)
648)             assert config == result_config, (
649)                 'stored config does not match expectation'
650)             )
651) 
652)     @pytest.mark.parametrize(['command_line', 'input', 'err_text'], [
653)         ([], b'', b'cannot update global settings without actual settings'),
654)         (
655)             ['sv'],
656)             b'',
657)             b'cannot update service settings without actual settings',
658)         ),
659)         (['--phrase', 'sv'], b'', b'no passphrase given'),
660)         (['--key'], b'', b'no valid SSH key selected'),
661)     ])
662)     def test_225_store_config_fail(
663)         self, monkeypatch: Any, command_line: list[str],
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

664)         input: bytes, err_text: bytes,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

665)     ) -> None:
666)         runner = click.testing.CliRunner(mix_stderr=False)
667)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
668)                                    config={'global': {'phrase': 'abc'},
669)                                            'services': {}}):
670)             monkeypatch.setattr(cli, '_get_suitable_ssh_keys',
671)                                 tests.suitable_ssh_keys)
672)             result = runner.invoke(cli.derivepassphrase,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

673)                                    ['--config', *command_line],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

674)                                    catch_exceptions=False, input=input)
675)             assert result.exit_code != 0, 'program unexpectedly succeeded?!'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

676)             assert result.stderr_bytes is not None
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

677)             assert err_text in result.stderr_bytes, (
678)                 'expected error message missing'
679)             )
680) 
681)     def test_225a_store_config_fail_manual_no_ssh_key_selection(
682)         self, monkeypatch: Any,
683)     ) -> None:
684)         runner = click.testing.CliRunner(mix_stderr=False)
685)         with tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
686)                                    config={'global': {'phrase': 'abc'},
687)                                            'services': {}}):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

688)             custom_error = 'custom error message'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

689)             def raiser():
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

690)                 raise RuntimeError(custom_error)
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

691)             monkeypatch.setattr(cli, '_select_ssh_key', raiser)
692)             result = runner.invoke(cli.derivepassphrase,
693)                                    ['--key', '--config'],
694)                                    catch_exceptions=False)
695)             assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

696)             assert result.stderr_bytes is not None
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

697)             assert custom_error.encode() in result.stderr_bytes, (
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

698)                 'expected error message missing'
699)             )
700) 
701)     def test_226_no_arguments(self) -> None:
702)         runner = click.testing.CliRunner(mix_stderr=False)
703)         result = runner.invoke(cli.derivepassphrase, [],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

704)                                catch_exceptions=False)
705)         assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

706)         assert result.stderr_bytes is not None
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

707)         assert b'SERVICE is required' in result.stderr_bytes, (
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

708)             'expected error message missing'
709)         )
710) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

711)     def test_226a_no_passphrase_or_key(self) -> None:
712)         runner = click.testing.CliRunner(mix_stderr=False)
713)         result = runner.invoke(cli.derivepassphrase, [DUMMY_SERVICE],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

714)                                catch_exceptions=False)
715)         assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

716)         assert result.stderr_bytes is not None
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

717)         assert b'no passphrase or key given' in result.stderr_bytes, (
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

718)             'expected error message missing'
719)         )
720) 
721) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

722) class TestCLIUtils:
723) 
724)     def test_100_save_bad_config(self, monkeypatch: Any) -> None:
725)         runner = click.testing.CliRunner()
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

726)         with (
727)             tests.isolated_config(monkeypatch=monkeypatch, runner=runner,
728)                                   config={}),
729)             pytest.raises(ValueError, match='Invalid vault config')
730)         ):
731)             cli._save_config(None)  # type: ignore
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

732) 
733) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

734)     def test_101_prompt_for_selection_multiple(self) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

735)         @click.command()
736)         @click.option('--heading', default='Our menu:')
737)         @click.argument('items', nargs=-1)
738)         def driver(heading, items):
739)             # from https://montypython.fandom.com/wiki/Spam#The_menu
740)             items = items or [
741)                 'Egg and bacon',
742)                 'Egg, sausage and bacon',
743)                 'Egg and spam',
744)                 'Egg, bacon and spam',
745)                 'Egg, bacon, sausage and spam',
746)                 'Spam, bacon, sausage and spam',
747)                 'Spam, egg, spam, spam, bacon and spam',
748)                 'Spam, spam, spam, egg and spam',
749)                 ('Spam, spam, spam, spam, spam, spam, baked beans, '
750)                  'spam, spam, spam and spam'),
751)                 ('Lobster thermidor aux crevettes with a mornay sauce '
752)                  'garnished with truffle paté, brandy '
753)                  'and a fried egg on top and spam'),
754)             ]
755)             index = cli._prompt_for_selection(items, heading=heading)
756)             click.echo('A fine choice: ', nl=False)
757)             click.echo(items[index])
758)             click.echo('(Note: Vikings strictly optional.)')
759)         runner = click.testing.CliRunner(mix_stderr=True)
760)         result = runner.invoke(driver, [], input='9')
761)         assert result.exit_code == 0, 'driver program failed'
762)         assert result.stdout == '''\
763) Our menu:
764) [1] Egg and bacon
765) [2] Egg, sausage and bacon
766) [3] Egg and spam
767) [4] Egg, bacon and spam
768) [5] Egg, bacon, sausage and spam
769) [6] Spam, bacon, sausage and spam
770) [7] Spam, egg, spam, spam, bacon and spam
771) [8] Spam, spam, spam, egg and spam
772) [9] Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
773) [10] Lobster thermidor aux crevettes with a mornay sauce garnished with truffle paté, brandy and a fried egg on top and spam
774) Your selection? (1-10, leave empty to abort): 9
775) A fine choice: Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
776) (Note: Vikings strictly optional.)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

777) ''', 'driver program produced unexpected output'  # noqa: E501
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

778)         result = runner.invoke(driver, ['--heading='], input='',
779)                                catch_exceptions=True)
780)         assert result.exit_code > 0, 'driver program succeeded?!'
781)         assert result.stdout == '''\
782) [1] Egg and bacon
783) [2] Egg, sausage and bacon
784) [3] Egg and spam
785) [4] Egg, bacon and spam
786) [5] Egg, bacon, sausage and spam
787) [6] Spam, bacon, sausage and spam
788) [7] Spam, egg, spam, spam, bacon and spam
789) [8] Spam, spam, spam, egg and spam
790) [9] Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
791) [10] Lobster thermidor aux crevettes with a mornay sauce garnished with truffle paté, brandy and a fried egg on top and spam
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

792) Your selection? (1-10, leave empty to abort): \n''', (  # noqa: E501
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

793)             'driver program produced unexpected output'
794)         )
795)         assert isinstance(result.exception, IndexError), (
796)             'driver program did not raise IndexError?!'
797)         )
798) 
799) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

800)     def test_102_prompt_for_selection_single(self) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

801)         @click.command()
802)         @click.option('--item', default='baked beans')
803)         @click.argument('prompt')
804)         def driver(item, prompt):
805)             try:
806)                 cli._prompt_for_selection([item], heading='',
807)                                           single_choice_prompt=prompt)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

808)             except IndexError:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

809)                 click.echo('Boo.')
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

810)                 raise
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

811)             else:
812)                 click.echo('Great!')
813)         runner = click.testing.CliRunner(mix_stderr=True)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

814)         result = runner.invoke(driver,
815)                                ['Will replace with spam. Confirm, y/n?'],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

816)                                input='y')
817)         assert result.exit_code == 0, 'driver program failed'
818)         assert result.stdout == '''\
819) [1] baked beans
820) Will replace with spam. Confirm, y/n? y
821) Great!
822) ''', 'driver program produced unexpected output'
823)         result = runner.invoke(driver,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

824)                                ['Will replace with spam, okay? '
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

825)                                 '(Please say "y" or "n".)'],
826)                                input='')
827)         assert result.exit_code > 0, 'driver program succeeded?!'
828)         assert result.stdout == '''\
829) [1] baked beans
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

830) Will replace with spam, okay? (Please say "y" or "n".):\x20
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

831) Boo.
832) ''', 'driver program produced unexpected output'
833)         assert isinstance(result.exception, IndexError), (
834)             'driver program did not raise IndexError?!'
835)         )
836) 
837) 
838)     def test_103_prompt_for_passphrase(self, monkeypatch: Any) -> None:
839)         monkeypatch.setattr(click, 'prompt',
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

840)                             lambda *a, **kw:
841)                                 json.dumps({'args': a, 'kwargs': kw}))
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

842)         res = json.loads(cli._prompt_for_passphrase())
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

843)         err_msg = 'missing arguments to passphrase prompt'
844)         assert 'args' in res, err_msg
845)         assert 'kwargs' in res, err_msg
846)         assert res['args'][:1] == ['Passphrase'], err_msg
847)         assert res['kwargs'].get('default') == '', err_msg
848)         assert not res['kwargs'].get('show_default', True), err_msg
849)         assert res['kwargs'].get('err'), err_msg
850)         assert res['kwargs'].get('hide_input'), err_msg
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

851) 
852) 
853)     @pytest.mark.parametrize(['command_line', 'config', 'result_config'], [
854)         (['--delete-globals'],
855)          {'global': {'phrase': 'abc'}, 'services': {}}, {'services': {}}),
856)         (['--delete', DUMMY_SERVICE],
857)          {'global': {'phrase': 'abc'},
858)           'services': {DUMMY_SERVICE: {'notes': '...'}}},
859)          {'global': {'phrase': 'abc'}, 'services': {}}),
860)         (['--clear'],
861)          {'global': {'phrase': 'abc'},
862)           'services': {DUMMY_SERVICE: {'notes': '...'}}},
863)          {'services': {}}),
864)     ])
865)     def test_203_repeated_config_deletion(
866)         self, monkeypatch: Any, command_line: list[str],
867)         config: dpp.types.VaultConfig, result_config: dpp.types.VaultConfig,
868)     ) -> None:
869)         runner = click.testing.CliRunner(mix_stderr=False)
870)         for start_config in [config, result_config]:
871)             with tests.isolated_config(monkeypatch=monkeypatch,
872)                                        runner=runner, config=start_config):
873)                 result = runner.invoke(cli.derivepassphrase, command_line,
874)                                        catch_exceptions=False)
875)                 assert (result.exit_code, result.stderr_bytes) == (0, b''), (
876)                     'program exited with failure'
877)                 )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

878)                 with open(cli._config_filename(), encoding='UTF-8') as infile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

879)                     config_readback = json.load(infile)
880)                 assert config_readback == result_config
881) 
882) 
883)     def test_204_phrase_from_key_manually(self) -> None:
884)         assert (
885)             dpp.Vault(phrase=DUMMY_PHRASE_FROM_KEY1, **DUMMY_CONFIG_SETTINGS)
886)             .generate(DUMMY_SERVICE) == DUMMY_RESULT_KEY1
887)         )
888) 
889) 
890)     @pytest.mark.parametrize(['vfunc', 'input'], [
891)         (cli._validate_occurrence_constraint, 20),
892)         (cli._validate_length, 20),
893)     ])
894)     def test_210a_validate_constraints_manually(
895)         self,
896)         vfunc: Callable[[click.Context, click.Parameter, Any], int | None],
897)         input: int,
898)     ) -> None:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

899)         ctx = cli.derivepassphrase.make_context(cli.PROG_NAME, [])
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

900)         param = cli.derivepassphrase.params[0]
901)         assert vfunc(ctx, param, input) == input
902) 
903) 
904)     @tests.skip_if_no_agent
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

905)     @pytest.mark.parametrize('conn_hint', ['none', 'socket', 'client'])
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

906)     def test_227_get_suitable_ssh_keys(
907)         self, monkeypatch: Any, conn_hint: str,
908)     ) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

909)         monkeypatch.setattr(ssh_agent_client.SSHAgentClient,
910)                             'list_keys', tests.list_keys)
911)         hint: ssh_agent_client.SSHAgentClient | socket.socket | None
912)         match conn_hint:
913)             case 'client':
914)                 hint = ssh_agent_client.SSHAgentClient()
915)             case 'socket':
916)                 hint = socket.socket(family=socket.AF_UNIX)
917)                 hint.connect(os.environ['SSH_AUTH_SOCK'])
918)             case _:
919)                 assert conn_hint == 'none'
920)                 hint = None
921)         exception: Exception | None = None
922)         try:
923)             list(cli._get_suitable_ssh_keys(hint))
924)         except RuntimeError:  # pragma: no cover
925)             pass
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

926)         except Exception as e:  # noqa: BLE001 # pragma: no cover
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

927)             exception = e
928)         finally: