2d292af3e81527750e46a2167d30efe840ac58ca
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 Create the configuration di...

Marco Ricci authored 1 month ago

10) import shutil
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

11) import socket
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 1 month ago

12) from typing import TYPE_CHECKING
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

19) import tests
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 1 month ago

20) from derivepassphrase import _types, cli, ssh_agent
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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 Avoid crashing when overrid...

Marco Ricci authored 1 month ago

38) DUMMY_KEY2_B64 = tests.DUMMY_KEY2_B64
39) DUMMY_KEY3 = tests.DUMMY_KEY3
40) DUMMY_KEY3_B64 = tests.DUMMY_KEY3_B64
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

41) 
42) 
43) class IncompatibleConfiguration(NamedTuple):
44)     other_options: list[tuple[str, ...]]
45)     needs_service: bool | None
46)     input: bytes | None
47) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

49) class SingleConfiguration(NamedTuple):
50)     needs_service: bool | None
51)     input: bytes | None
52)     check_success: bool
53) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

55) class OptionCombination(NamedTuple):
56)     options: list[str]
57)     incompatible: bool
58)     needs_service: bool | None
59)     input: bytes | None
60)     check_success: bool
61) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

63) PASSWORD_GENERATION_OPTIONS: list[tuple[str, ...]] = [
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

64)     ('--phrase',),
65)     ('--key',),
66)     ('--length', '20'),
67)     ('--repeat', '20'),
68)     ('--lower', '1'),
69)     ('--upper', '1'),
70)     ('--number', '1'),
71)     ('--space', '1'),
72)     ('--dash', '1'),
73)     ('--symbol', '1'),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

74) ]
75) CONFIGURATION_OPTIONS: list[tuple[str, ...]] = [
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

76)     ('--notes',),
77)     ('--config',),
78)     ('--delete',),
79)     ('--delete-globals',),
80)     ('--clear',),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

81) ]
82) CONFIGURATION_COMMANDS: list[tuple[str, ...]] = [
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

83)     ('--notes',),
84)     ('--delete',),
85)     ('--delete-globals',),
86)     ('--clear',),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

87) ]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

88) STORAGE_OPTIONS: list[tuple[str, ...]] = [('--export', '-'), ('--import', '-')]
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

89) INCOMPATIBLE: dict[tuple[str, ...], IncompatibleConfiguration] = {
90)     ('--phrase',): IncompatibleConfiguration(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

91)         [('--key',), *CONFIGURATION_COMMANDS, *STORAGE_OPTIONS],
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

92)         True,
93)         DUMMY_PASSPHRASE,
94)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

95)     ('--key',): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

96)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
97)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

98)     ('--length', '20'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

99)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
100)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

101)     ('--repeat', '20'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

102)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
103)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

104)     ('--lower', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

105)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
106)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

107)     ('--upper', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

108)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
109)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

110)     ('--number', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

111)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
112)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

113)     ('--space', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

114)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
115)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

116)     ('--dash', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

117)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
118)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

119)     ('--symbol', '1'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

120)         CONFIGURATION_COMMANDS + STORAGE_OPTIONS, True, DUMMY_PASSPHRASE
121)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

122)     ('--notes',): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

123)         [
124)             ('--config',),
125)             ('--delete',),
126)             ('--delete-globals',),
127)             ('--clear',),
128)             *STORAGE_OPTIONS,
129)         ],
130)         True,
131)         None,
132)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

133)     ('--config', '-p'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

134)         [('--delete',), ('--delete-globals',), ('--clear',), *STORAGE_OPTIONS],
135)         None,
136)         DUMMY_PASSPHRASE,
137)     ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

138)     ('--delete',): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

141)     ('--delete-globals',): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

144)     ('--clear',): IncompatibleConfiguration(STORAGE_OPTIONS, False, None),
145)     ('--export', '-'): IncompatibleConfiguration(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

146)         [('--import', '-')], False, None
147)     ),
148)     ('--import', '-'): IncompatibleConfiguration([], False, None),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

149) }
150) SINGLES: dict[tuple[str, ...], SingleConfiguration] = {
151)     ('--phrase',): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
152)     ('--key',): SingleConfiguration(True, None, False),
153)     ('--length', '20'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
154)     ('--repeat', '20'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
155)     ('--lower', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
156)     ('--upper', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
157)     ('--number', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
158)     ('--space', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
159)     ('--dash', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
160)     ('--symbol', '1'): SingleConfiguration(True, DUMMY_PASSPHRASE, True),
161)     ('--notes',): SingleConfiguration(True, None, False),
162)     ('--config', '-p'): SingleConfiguration(None, DUMMY_PASSPHRASE, False),
163)     ('--delete',): SingleConfiguration(True, None, False),
164)     ('--delete-globals',): SingleConfiguration(False, None, True),
165)     ('--clear',): SingleConfiguration(False, None, True),
166)     ('--export', '-'): SingleConfiguration(False, None, True),
167)     ('--import', '-'): SingleConfiguration(False, b'{"services": {}}', True),
168) }
169) INTERESTING_OPTION_COMBINATIONS: list[OptionCombination] = []
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

171) for opt, config in INCOMPATIBLE.items():
172)     for opt2 in config.other_options:
173)         INTERESTING_OPTION_COMBINATIONS.extend([
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

174)             OptionCombination(
175)                 options=list(opt + opt2),
176)                 incompatible=True,
177)                 needs_service=config.needs_service,
178)                 input=config.input,
179)                 check_success=False,
180)             ),
181)             OptionCombination(
182)                 options=list(opt2 + opt),
183)                 incompatible=True,
184)                 needs_service=config.needs_service,
185)                 input=config.input,
186)                 check_success=False,
187)             ),
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

188)         ])
189) for opt, config in SINGLES.items():
190)     INTERESTING_OPTION_COMBINATIONS.append(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

191)         OptionCombination(
192)             options=list(opt),
193)             incompatible=False,
194)             needs_service=config.needs_service,
195)             input=config.input,
196)             check_success=config.check_success,
197)         )
198)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

199) 
200) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

201) class TestCLI:
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

202)     def test_200_help_output(self, monkeypatch: Any) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

203)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

204)         with tests.isolated_config(
205)             monkeypatch=monkeypatch,
206)             runner=runner,
207)             config={'services': {}},
208)         ):
209)             result = runner.invoke(
210)                 cli.derivepassphrase, ['--help'], catch_exceptions=False
211)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

212)         assert result.exit_code == 0
213)         assert (
214)             'Password generation:\n' in result.output
215)         ), 'Option groups not respected in help text.'
216)         assert (
217)             'Use NUMBER=0, e.g. "--symbol 0"' in result.output
218)         ), 'Option group epilog not printed.'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

219) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

223)     def test_201_disable_character_set(
224)         self, monkeypatch: Any, charset_name: str
225)     ) -> None:
226)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
227)         option = f'--{charset_name}'
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

228)         charset = dpp.vault.Vault._CHARSETS[charset_name].decode('ascii')
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

229)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

230)         with tests.isolated_config(
231)             monkeypatch=monkeypatch,
232)             runner=runner,
233)             config={'services': {}},
234)         ):
235)             result = runner.invoke(
236)                 cli.derivepassphrase,
237)                 [option, '0', '-p', DUMMY_SERVICE],
238)                 input=DUMMY_PASSPHRASE,
239)                 catch_exceptions=False,
240)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

241)         assert (
242)             result.exit_code == 0
243)         ), f'program died unexpectedly with exit code {result.exit_code}'
244)         assert (
245)             not result.stderr_bytes
246)         ), f'program barfed on stderr: {result.stderr_bytes!r}'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

247)         for c in charset:
248)             assert c not in result.stdout, (
249)                 f'derived password contains forbidden character {c!r}: '
250)                 f'{result.stdout!r}'
251)             )
Marco Ricci Add prototype command-line...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

253)     def test_202_disable_repetition(self, monkeypatch: Any) -> None:
254)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
255)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

256)         with tests.isolated_config(
257)             monkeypatch=monkeypatch,
258)             runner=runner,
259)             config={'services': {}},
260)         ):
261)             result = runner.invoke(
262)                 cli.derivepassphrase,
263)                 ['--repeat', '0', '-p', DUMMY_SERVICE],
264)                 input=DUMMY_PASSPHRASE,
265)                 catch_exceptions=False,
266)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

267)         assert (
268)             result.exit_code == 0
269)         ), f'program died unexpectedly with exit code {result.exit_code}'
270)         assert (
271)             not result.stderr_bytes
272)         ), f'program barfed on stderr: {result.stderr_bytes!r}'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

273)         passphrase = result.stdout.rstrip('\r\n')
274)         for i in range(len(passphrase) - 1):
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

279) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

280)     @pytest.mark.parametrize(
281)         'config',
282)         [
283)             pytest.param(
284)                 {
285)                     'global': {'key': DUMMY_KEY1_B64},
286)                     'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS},
287)                 },
288)                 id='global',
289)             ),
290)             pytest.param(
291)                 {
292)                     'global': {
293)                         'phrase': DUMMY_PASSPHRASE.rstrip(b'\n').decode(
294)                             'ASCII'
295)                         )
296)                     },
297)                     'services': {
298)                         DUMMY_SERVICE: {
299)                             'key': DUMMY_KEY1_B64,
300)                             **DUMMY_CONFIG_SETTINGS,
301)                         }
302)                     },
303)                 },
304)                 id='service',
305)             ),
306)         ],
307)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

308)     def test_204a_key_from_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

309)         self,
310)         monkeypatch: Any,
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 1 month ago

311)         config: _types.VaultConfig,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

312)     ) -> None:
313)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

314)         with tests.isolated_config(
315)             monkeypatch=monkeypatch, runner=runner, config=config
316)         ):
317)             monkeypatch.setattr(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

318)                 dpp.vault.Vault, 'phrase_from_key', tests.phrase_from_key
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

319)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

320)             result = runner.invoke(
321)                 cli.derivepassphrase, [DUMMY_SERVICE], catch_exceptions=False
322)             )
323)             assert (result.exit_code, result.stderr_bytes) == (
324)                 0,
325)                 b'',
326)             ), 'program exited with failure'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

327)             assert (
328)                 result.stdout_bytes.rstrip(b'\n') != DUMMY_RESULT_PASSPHRASE
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

329)             ), 'program generated unexpected result (phrase instead of key)'
330)             assert (
331)                 result.stdout_bytes.rstrip(b'\n') == DUMMY_RESULT_KEY1
332)             ), 'program generated unexpected result (wrong settings?)'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

334)     def test_204b_key_from_command_line(self, monkeypatch: Any) -> None:
335)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

336)         with tests.isolated_config(
337)             monkeypatch=monkeypatch,
338)             runner=runner,
339)             config={'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
340)         ):
341)             monkeypatch.setattr(
342)                 cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys
343)             )
344)             monkeypatch.setattr(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

345)                 dpp.vault.Vault, 'phrase_from_key', tests.phrase_from_key
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

346)             )
347)             result = runner.invoke(
348)                 cli.derivepassphrase,
349)                 ['-k', DUMMY_SERVICE],
350)                 input=b'1\n',
351)                 catch_exceptions=False,
352)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

353)             assert result.exit_code == 0, 'program exited with failure'
354)             assert result.stdout_bytes, 'program output expected'
355)             last_line = result.stdout_bytes.splitlines(True)[-1]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

356)             assert (
357)                 last_line.rstrip(b'\n') != DUMMY_RESULT_PASSPHRASE
358)             ), 'program generated unexpected result (phrase instead of key)'
359)             assert (
360)                 last_line.rstrip(b'\n') == DUMMY_RESULT_KEY1
361)             ), 'program generated unexpected result (wrong settings?)'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

362) 
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

363)     @tests.skip_if_no_agent
364)     @pytest.mark.parametrize(
365)         'config',
366)         [
367)             pytest.param(
368)                 {
369)                     'global': {'key': DUMMY_KEY1_B64},
370)                     'services': {DUMMY_SERVICE: {}},
371)                 },
372)                 id='global_config',
373)             ),
374)             pytest.param(
375)                 {'services': {DUMMY_SERVICE: {'key': DUMMY_KEY2_B64}}},
376)                 id='service_config',
377)             ),
378)             pytest.param(
379)                 {
380)                     'global': {'key': DUMMY_KEY1_B64},
381)                     'services': {DUMMY_SERVICE: {'key': DUMMY_KEY2_B64}},
382)                 },
383)                 id='full_config',
384)             ),
385)         ],
386)     )
387)     @pytest.mark.parametrize('key_index', [1, 2, 3], ids=lambda i: f'index{i}')
388)     def test_204c_key_override_on_command_line(
389)         self,
390)         monkeypatch: Any,
391)         config: dict[str, Any],
392)         key_index: int,
393)     ) -> None:
394)         def sign(
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 weeks ago

395)             _: Any, key: bytes | bytearray, message: bytes | bytearray
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

396)         ) -> bytes:
397)             del message  # Unused.
398)             for value in tests.SUPPORTED_KEYS.values():
399)                 if value['public_key_data'] == key:
400)                     assert value['expected_signature'] is not None
401)                     return value['expected_signature']
402)             raise AssertionError
403) 
404)         monkeypatch.setattr(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

405)             ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

406)         )
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

407)         monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', sign)
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

408)         runner = click.testing.CliRunner(mix_stderr=False)
409)         with tests.isolated_config(
410)             monkeypatch=monkeypatch, runner=runner, config=config
411)         ):
412)             result = runner.invoke(
413)                 cli.derivepassphrase,
414)                 ['-k', DUMMY_SERVICE],
415)                 input=f'{key_index}\n'.encode('ASCII'),
416)             )
417)             assert result.stderr_bytes is not None
418)             assert (
419)                 b'Error:' not in result.stderr_bytes
420)             ), 'program exited with failure'
421)             assert result.stdout_bytes, 'program output expected'
422)             assert result.exit_code == 0, 'program exited with failure'
423) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

424)     def test_205_service_phrase_if_key_in_global_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

425)         self,
426)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

427)     ) -> None:
428)         runner = click.testing.CliRunner(mix_stderr=False)
429)         with tests.isolated_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

430)             monkeypatch=monkeypatch,
431)             runner=runner,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

432)             config={
433)                 'global': {'key': DUMMY_KEY1_B64},
434)                 'services': {
435)                     DUMMY_SERVICE: {
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

436)                         'phrase': DUMMY_PASSPHRASE.rstrip(b'\n').decode(
437)                             'ASCII'
438)                         ),
439)                         **DUMMY_CONFIG_SETTINGS,
440)                     }
441)                 },
442)             },
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

443)         ):
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

444)             result = runner.invoke(
445)                 cli.derivepassphrase, [DUMMY_SERVICE], catch_exceptions=False
446)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

447)             assert result.exit_code == 0, 'program exited with failure'
448)             assert result.stdout_bytes, 'program output expected'
449)             last_line = result.stdout_bytes.splitlines(True)[-1]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

450)             assert (
451)                 last_line.rstrip(b'\n') != DUMMY_RESULT_KEY1
452)             ), 'program generated unexpected result (key instead of phrase)'
453)             assert (
454)                 last_line.rstrip(b'\n') == DUMMY_RESULT_PASSPHRASE
455)             ), 'program generated unexpected result (wrong settings?)'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

456) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

457)     @pytest.mark.parametrize(
458)         'option',
459)         [
460)             '--lower',
461)             '--upper',
462)             '--number',
463)             '--space',
464)             '--dash',
465)             '--symbol',
466)             '--repeat',
467)             '--length',
468)         ],
469)     )
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

470)     def test_210_invalid_argument_range(
471)         self, monkeypatch: Any, option: str
472)     ) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

473)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

474)         with tests.isolated_config(
475)             monkeypatch=monkeypatch,
476)             runner=runner,
477)             config={'services': {}},
478)         ):
479)             for value in '-42', 'invalid':
480)                 result = runner.invoke(
481)                     cli.derivepassphrase,
482)                     [option, value, '-p', DUMMY_SERVICE],
483)                     input=DUMMY_PASSPHRASE,
484)                     catch_exceptions=False,
485)                 )
486)                 assert result.exit_code > 0, 'program unexpectedly succeeded'
487)                 assert (
488)                     result.stderr_bytes
489)                 ), 'program did not print any error message'
490)                 assert (
491)                     b'Error: Invalid value' in result.stderr_bytes
492)                 ), 'program did not print the expected error message'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

493) 
494)     @pytest.mark.parametrize(
495)         ['options', 'service', 'input', 'check_success'],
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

496)         [
497)             (o.options, o.needs_service, o.input, o.check_success)
498)             for o in INTERESTING_OPTION_COMBINATIONS
499)             if not o.incompatible
500)         ],
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

501)     )
502)     def test_211_service_needed(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

503)         self,
504)         monkeypatch: Any,
505)         options: list[str],
506)         service: bool | None,
507)         input: bytes | None,
508)         check_success: bool,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

509)     ) -> None:
510)         monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)
511)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

512)         with tests.isolated_config(
513)             monkeypatch=monkeypatch,
514)             runner=runner,
515)             config={'global': {'phrase': 'abc'}, 'services': {}},
516)         ):
517)             result = runner.invoke(
518)                 cli.derivepassphrase,
519)                 options if service else [*options, DUMMY_SERVICE],
520)                 input=input,
521)                 catch_exceptions=False,
522)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

523)             if service is not None:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

524)                 assert result.exit_code > 0, 'program unexpectedly succeeded'
525)                 assert (
526)                     result.stderr_bytes
527)                 ), 'program did not print any error message'
528)                 err_msg = (
529)                     b' requires a SERVICE'
530)                     if service
531)                     else b' does not take a SERVICE argument'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

532)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

533)                 assert (
534)                     err_msg in result.stderr_bytes
535)                 ), 'program did not print the expected error message'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

536)             else:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

537)                 assert (result.exit_code, result.stderr_bytes) == (
538)                     0,
539)                     b'',
540)                 ), 'program unexpectedly failed'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

541)         if check_success:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

542)             with tests.isolated_config(
543)                 monkeypatch=monkeypatch,
544)                 runner=runner,
545)                 config={'global': {'phrase': 'abc'}, 'services': {}},
546)             ):
547)                 monkeypatch.setattr(
548)                     cli, '_prompt_for_passphrase', tests.auto_prompt
549)                 )
550)                 result = runner.invoke(
551)                     cli.derivepassphrase,
552)                     [*options, DUMMY_SERVICE] if service else options,
553)                     input=input,
554)                     catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

555)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

556)                 assert (result.exit_code, result.stderr_bytes) == (
557)                     0,
558)                     b'',
559)                 ), 'program unexpectedly failed'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

560) 
561)     @pytest.mark.parametrize(
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

562)         ['options', 'service'],
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

563)         [
564)             (o.options, o.needs_service)
565)             for o in INTERESTING_OPTION_COMBINATIONS
566)             if o.incompatible
567)         ],
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

569)     def test_212_incompatible_options(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

570)         self,
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

571)         monkeypatch: Any,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

574)     ) -> None:
575)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

576)         with tests.isolated_config(
577)             monkeypatch=monkeypatch,
578)             runner=runner,
579)             config={'services': {}},
580)         ):
581)             result = runner.invoke(
582)                 cli.derivepassphrase,
583)                 [*options, DUMMY_SERVICE] if service else options,
584)                 input=DUMMY_PASSPHRASE,
585)                 catch_exceptions=False,
586)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

587)         assert result.exit_code > 0, 'program unexpectedly succeeded'
588)         assert result.stderr_bytes, 'program did not print any error message'
589)         assert (
590)             b'mutually exclusive with ' in result.stderr_bytes
591)         ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

593)     def test_213_import_bad_config_not_vault_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

594)         self,
595)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

596)     ) -> None:
597)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

598)         with tests.isolated_config(
599)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
600)         ):
601)             result = runner.invoke(
602)                 cli.derivepassphrase,
603)                 ['--import', '-'],
604)                 input=b'null',
605)                 catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

606)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

607)             assert result.exit_code > 0, 'program unexpectedly succeeded'
608)             assert (
609)                 result.stderr_bytes
610)             ), 'program did not print any error message'
611)             assert (
Marco Ricci Use better error message ha...

Marco Ricci authored 1 month ago

612)                 b'Invalid vault config' in result.stderr_bytes
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

613)             ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

615)     def test_213a_import_bad_config_not_json_data(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

616)         self,
617)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

618)     ) -> None:
619)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

620)         with tests.isolated_config(
621)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
622)         ):
623)             result = runner.invoke(
624)                 cli.derivepassphrase,
625)                 ['--import', '-'],
626)                 input=b'This string is not valid JSON.',
627)                 catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

628)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

629)             assert result.exit_code > 0, 'program unexpectedly succeeded'
630)             assert (
631)                 result.stderr_bytes
632)             ), 'program did not print any error message'
633)             assert (
634)                 b'cannot decode JSON' in result.stderr_bytes
635)             ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

637)     def test_213b_import_bad_config_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

638)         self,
639)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

640)     ) -> None:
641)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

642)         # `isolated_config` validates the configuration.  So, to pass an
643)         # actual broken configuration, we must open the configuration file
644)         # ourselves afterwards, inside the context.
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

645)         with tests.isolated_config(
646)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
647)         ):
648)             with open(
649)                 cli._config_filename(), 'w', encoding='UTF-8'
650)             ) as outfile:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

655)                 ['--import', os.fsdecode(dname)],
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

657)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

658)             assert result.exit_code > 0, 'program unexpectedly succeeded'
659)             assert (
660)                 result.stderr_bytes
661)             ), 'program did not print any error message'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

662)             # Don't test the actual error message, because it is subject to
663)             # locale settings.  TODO: find a way anyway.
664) 
665)     def test_214_export_settings_no_stored_settings(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

666)         self,
667)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

668)     ) -> None:
669)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

674)                 os.remove(cli._config_filename())
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

675)             result = runner.invoke(
676)                 cli.derivepassphrase, ['--export', '-'], catch_exceptions=False
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

677)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

678)             assert (result.exit_code, result.stderr_bytes) == (
679)                 0,
680)                 b'',
681)             ), 'program exited with failure'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

683)     def test_214a_export_settings_bad_stored_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

684)         self,
685)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

686)     ) -> None:
687)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

688)         with tests.isolated_config(
689)             monkeypatch=monkeypatch, runner=runner, config={}
690)         ):
691)             result = runner.invoke(
692)                 cli.derivepassphrase,
693)                 ['--export', '-'],
694)                 input=b'null',
695)                 catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

696)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

697)             assert result.exit_code > 0, 'program unexpectedly succeeded'
698)             assert (
699)                 result.stderr_bytes
700)             ), 'program did not print any error message'
701)             assert (
Marco Ricci Use better error message ha...

Marco Ricci authored 1 month ago

702)                 b'Cannot load config' in result.stderr_bytes
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

703)             ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

705)     def test_214b_export_settings_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

706)         self,
707)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

708)     ) -> None:
709)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

714)                 os.remove(cli._config_filename())
715)             os.makedirs(cli._config_filename())
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

716)             result = runner.invoke(
717)                 cli.derivepassphrase,
718)                 ['--export', '-'],
719)                 input=b'null',
720)                 catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

721)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

722)             assert result.exit_code > 0, 'program unexpectedly succeeded'
723)             assert (
724)                 result.stderr_bytes
725)             ), 'program did not print any error message'
726)             assert (
Marco Ricci Use better error message ha...

Marco Ricci authored 1 month ago

727)                 b'Cannot load config' in result.stderr_bytes
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

728)             ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

730)     def test_214c_export_settings_target_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

731)         self,
732)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

733)     ) -> None:
734)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

735)         with tests.isolated_config(
736)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
737)         ):
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

738)             dname = os.path.dirname(cli._config_filename())
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

739)             result = runner.invoke(
740)                 cli.derivepassphrase,
741)                 ['--export', os.fsdecode(dname)],
742)                 input=b'null',
743)                 catch_exceptions=False,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

744)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

745)             assert result.exit_code > 0, 'program unexpectedly succeeded'
746)             assert (
747)                 result.stderr_bytes
748)             ), 'program did not print any error message'
749)             assert (
Marco Ricci Use better error message ha...

Marco Ricci authored 1 month ago

750)                 b'Cannot store config' in result.stderr_bytes
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

751)             ), 'program did not print the expected error message'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

752) 
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

753)     def test_214d_export_settings_settings_directory_not_a_directory(
754)         self,
755)         monkeypatch: Any,
756)     ) -> None:
757)         runner = click.testing.CliRunner(mix_stderr=False)
758)         with tests.isolated_config(
759)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
760)         ):
761)             with contextlib.suppress(FileNotFoundError):
762)                 shutil.rmtree('.derivepassphrase')
763)             with open('.derivepassphrase', 'w', encoding='UTF-8') as outfile:
764)                 print('Obstruction!!', file=outfile)
765)             result = runner.invoke(
766)                 cli.derivepassphrase,
767)                 ['--export', '-'],
768)                 input=b'null',
769)                 catch_exceptions=False,
770)             )
771)             assert result.exit_code > 0, 'program unexpectedly succeeded'
772)             assert (
773)                 result.stderr_bytes
774)             ), 'program did not print any error message'
775)             assert (
Marco Ricci Use better error message ha...

Marco Ricci authored 1 month ago

776)                 b'Cannot load config' in result.stderr_bytes
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

777)             ), 'program did not print the expected error message'
778) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

779)     def test_220_edit_notes_successfully(self, monkeypatch: Any) -> None:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

780)         edit_result = """
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

781) 
782) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
783) contents go here
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

784) """
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

785)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

786)         with tests.isolated_config(
787)             monkeypatch=monkeypatch,
788)             runner=runner,
789)             config={'global': {'phrase': 'abc'}, 'services': {}},
790)         ):
791)             monkeypatch.setattr(click, 'edit', lambda *a, **kw: edit_result)  # noqa: ARG005
792)             result = runner.invoke(
793)                 cli.derivepassphrase, ['--notes', 'sv'], catch_exceptions=False
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

794)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

795)             assert (result.exit_code, result.stderr_bytes) == (
796)                 0,
797)                 b'',
798)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

800)                 config = json.load(infile)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

801)             assert config == {
802)                 'global': {'phrase': 'abc'},
803)                 'services': {'sv': {'notes': 'contents go here'}},
804)             }
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

805) 
806)     def test_221_edit_notes_noop(self, monkeypatch: Any) -> None:
807)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

808)         with tests.isolated_config(
809)             monkeypatch=monkeypatch,
810)             runner=runner,
811)             config={'global': {'phrase': 'abc'}, 'services': {}},
812)         ):
813)             monkeypatch.setattr(click, 'edit', lambda *a, **kw: None)  # noqa: ARG005
814)             result = runner.invoke(
815)                 cli.derivepassphrase, ['--notes', 'sv'], catch_exceptions=False
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

816)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

817)             assert (result.exit_code, result.stderr_bytes) == (
818)                 0,
819)                 b'',
820)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

822)                 config = json.load(infile)
823)             assert config == {'global': {'phrase': 'abc'}, 'services': {}}
824) 
825)     def test_222_edit_notes_marker_removed(self, monkeypatch: Any) -> None:
826)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

827)         with tests.isolated_config(
828)             monkeypatch=monkeypatch,
829)             runner=runner,
830)             config={'global': {'phrase': 'abc'}, 'services': {}},
831)         ):
832)             monkeypatch.setattr(click, 'edit', lambda *a, **kw: 'long\ntext')  # noqa: ARG005
833)             result = runner.invoke(
834)                 cli.derivepassphrase, ['--notes', 'sv'], catch_exceptions=False
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

835)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

836)             assert (result.exit_code, result.stderr_bytes) == (
837)                 0,
838)                 b'',
839)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

841)                 config = json.load(infile)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

842)             assert config == {
843)                 'global': {'phrase': 'abc'},
844)                 'services': {'sv': {'notes': 'long\ntext'}},
845)             }
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

846) 
847)     def test_223_edit_notes_abort(self, monkeypatch: Any) -> None:
848)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

849)         with tests.isolated_config(
850)             monkeypatch=monkeypatch,
851)             runner=runner,
852)             config={'global': {'phrase': 'abc'}, 'services': {}},
853)         ):
854)             monkeypatch.setattr(click, 'edit', lambda *a, **kw: '\n\n')  # noqa: ARG005
855)             result = runner.invoke(
856)                 cli.derivepassphrase, ['--notes', 'sv'], catch_exceptions=False
857)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

858)             assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

859)             assert result.stderr_bytes is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

864)                 config = json.load(infile)
865)             assert config == {'global': {'phrase': 'abc'}, 'services': {}}
866) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

867)     @pytest.mark.parametrize(
868)         ['command_line', 'input', 'result_config'],
869)         [
870)             (
871)                 ['--phrase'],
872)                 b'my passphrase\n',
873)                 {'global': {'phrase': 'my passphrase'}, 'services': {}},
874)             ),
875)             (
876)                 ['--key'],
877)                 b'1\n',
878)                 {'global': {'key': DUMMY_KEY1_B64}, 'services': {}},
879)             ),
880)             (
881)                 ['--phrase', 'sv'],
882)                 b'my passphrase\n',
883)                 {
884)                     'global': {'phrase': 'abc'},
885)                     'services': {'sv': {'phrase': 'my passphrase'}},
886)                 },
887)             ),
888)             (
889)                 ['--key', 'sv'],
890)                 b'1\n',
891)                 {
892)                     'global': {'phrase': 'abc'},
893)                     'services': {'sv': {'key': DUMMY_KEY1_B64}},
894)                 },
895)             ),
896)             (
897)                 ['--key', '--length', '15', 'sv'],
898)                 b'1\n',
899)                 {
900)                     'global': {'phrase': 'abc'},
901)                     'services': {'sv': {'key': DUMMY_KEY1_B64, 'length': 15}},
902)                 },
903)             ),
904)         ],
905)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

906)     def test_224_store_config_good(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

907)         self,
908)         monkeypatch: Any,
909)         command_line: list[str],
910)         input: bytes,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

911)         result_config: Any,
912)     ) -> None:
913)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

914)         with tests.isolated_config(
915)             monkeypatch=monkeypatch,
916)             runner=runner,
917)             config={'global': {'phrase': 'abc'}, 'services': {}},
918)         ):
919)             monkeypatch.setattr(
920)                 cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys
921)             )
922)             result = runner.invoke(
923)                 cli.derivepassphrase,
924)                 ['--config', *command_line],
925)                 catch_exceptions=False,
926)                 input=input,
927)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

928)             assert result.exit_code == 0, 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

930)                 config = json.load(infile)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

931)             assert (
932)                 config == result_config
933)             ), 'stored config does not match expectation'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

934) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

935)     @pytest.mark.parametrize(
936)         ['command_line', 'input', 'err_text'],
937)         [
938)             (
939)                 [],
940)                 b'',
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 1 month ago

941)                 b'Cannot update global settings without actual settings',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

942)             ),
943)             (
944)                 ['sv'],
945)                 b'',
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 1 month ago

946)                 b'Cannot update service settings without actual settings',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

947)             ),
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 1 month ago

948)             (['--phrase', 'sv'], b'', b'No passphrase given'),
949)             (['--key'], b'', b'No valid SSH key selected'),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

950)         ],
951)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

952)     def test_225_store_config_fail(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

953)         self,
954)         monkeypatch: Any,
955)         command_line: list[str],
956)         input: bytes,
957)         err_text: bytes,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

958)     ) -> None:
959)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

960)         with tests.isolated_config(
961)             monkeypatch=monkeypatch,
962)             runner=runner,
963)             config={'global': {'phrase': 'abc'}, 'services': {}},
964)         ):
965)             monkeypatch.setattr(
966)                 cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys
967)             )
968)             result = runner.invoke(
969)                 cli.derivepassphrase,
970)                 ['--config', *command_line],
971)                 catch_exceptions=False,
972)                 input=input,
973)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

974)             assert result.exit_code != 0, 'program unexpectedly succeeded?!'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

975)             assert result.stderr_bytes is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

976)             assert (
977)                 err_text in result.stderr_bytes
978)             ), 'expected error message missing'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

979) 
980)     def test_225a_store_config_fail_manual_no_ssh_key_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

981)         self,
982)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

983)     ) -> None:
984)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

985)         with tests.isolated_config(
986)             monkeypatch=monkeypatch,
987)             runner=runner,
988)             config={'global': {'phrase': 'abc'}, 'services': {}},
989)         ):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

990)             custom_error = 'custom error message'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

991) 
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 1 month ago

992)             def raiser() -> None:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

993)                 raise RuntimeError(custom_error)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

995)             monkeypatch.setattr(cli, '_select_ssh_key', raiser)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

996)             result = runner.invoke(
997)                 cli.derivepassphrase,
998)                 ['--key', '--config'],
999)                 catch_exceptions=False,
1000)             )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1001)             assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

1002)             assert result.stderr_bytes is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1003)             assert (
1004)                 custom_error.encode() in result.stderr_bytes
1005)             ), 'expected error message missing'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1006) 
Marco Ricci Add missing tests for rewor...

Marco Ricci authored 1 month ago

1007)     def test_225b_store_config_fail_manual_no_ssh_agent(
1008)         self,
1009)         monkeypatch: Any,
1010)     ) -> None:
1011)         runner = click.testing.CliRunner(mix_stderr=False)
1012)         with tests.isolated_config(
1013)             monkeypatch=monkeypatch,
1014)             runner=runner,
1015)             config={'global': {'phrase': 'abc'}, 'services': {}},
1016)         ):
1017)             monkeypatch.delenv('SSH_AUTH_SOCK', raising=False)
1018)             result = runner.invoke(
1019)                 cli.derivepassphrase,
1020)                 ['--key', '--config'],
1021)                 catch_exceptions=False,
1022)             )
1023)             assert result.exit_code != 0, 'program unexpectedly succeeded'
1024)             assert result.stderr_bytes is not None
1025)             assert (
1026)                 b'Cannot find running SSH agent' in result.stderr_bytes
1027)             ), 'expected error message missing'
1028) 
1029)     def test_225c_store_config_fail_manual_bad_ssh_agent_connection(
1030)         self,
1031)         monkeypatch: Any,
1032)     ) -> None:
1033)         runner = click.testing.CliRunner(mix_stderr=False)
1034)         with tests.isolated_config(
1035)             monkeypatch=monkeypatch,
1036)             runner=runner,
1037)             config={'global': {'phrase': 'abc'}, 'services': {}},
1038)         ):
1039)             monkeypatch.setenv('SSH_AUTH_SOCK', os.getcwd())
1040)             result = runner.invoke(
1041)                 cli.derivepassphrase,
1042)                 ['--key', '--config'],
1043)                 catch_exceptions=False,
1044)             )
1045)             assert result.exit_code != 0, 'program unexpectedly succeeded'
1046)             assert result.stderr_bytes is not None
1047)             assert (
1048)                 b'Cannot connect to SSH agent' in result.stderr_bytes
1049)             ), 'expected error message missing'
1050) 
1051)     @pytest.mark.parametrize('try_race_free_implementation', [True, False])
1052)     def test_225d_store_config_fail_manual_read_only_file(
1053)         self,
1054)         monkeypatch: Any,
1055)         try_race_free_implementation: bool,
1056)     ) -> None:
1057)         runner = click.testing.CliRunner(mix_stderr=False)
1058)         with tests.isolated_config(
1059)             monkeypatch=monkeypatch,
1060)             runner=runner,
1061)             config={'global': {'phrase': 'abc'}, 'services': {}},
1062)         ):
1063)             tests.make_file_readonly(
1064)                 cli._config_filename(),
1065)                 try_race_free_implementation=try_race_free_implementation,
1066)             )
1067)             result = runner.invoke(
1068)                 cli.derivepassphrase,
1069)                 ['--config', '--length=15', DUMMY_SERVICE],
1070)                 catch_exceptions=False,
1071)             )
1072)             assert result.exit_code != 0, 'program unexpectedly succeeded'
1073)             assert result.stderr_bytes is not None
1074)             assert (
1075)                 b'Cannot store config' in result.stderr_bytes
1076)             ), 'expected error message missing'
1077) 
1078)     def test_225e_store_config_fail_manual_custom_error(
1079)         self,
1080)         monkeypatch: Any,
1081)     ) -> None:
1082)         runner = click.testing.CliRunner(mix_stderr=False)
1083)         with tests.isolated_config(
1084)             monkeypatch=monkeypatch,
1085)             runner=runner,
1086)             config={'global': {'phrase': 'abc'}, 'services': {}},
1087)         ):
1088)             custom_error = 'custom error message'
1089) 
1090)             def raiser(config: Any) -> None:
1091)                 del config
1092)                 raise RuntimeError(custom_error)
1093) 
1094)             monkeypatch.setattr(cli, '_save_config', raiser)
1095)             result = runner.invoke(
1096)                 cli.derivepassphrase,
1097)                 ['--config', '--length=15', DUMMY_SERVICE],
1098)                 catch_exceptions=False,
1099)             )
1100)             assert result.exit_code != 0, 'program unexpectedly succeeded'
1101)             assert result.stderr_bytes is not None
1102)             assert (
1103)                 custom_error.encode() in result.stderr_bytes
1104)             ), 'expected error message missing'
1105) 
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

1106)     def test_226_no_arguments(self, monkeypatch: Any) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1107)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

1108)         with tests.isolated_config(
1109)             monkeypatch=monkeypatch,
1110)             runner=runner,
1111)             config={'services': {}},
1112)         ):
1113)             result = runner.invoke(
1114)                 cli.derivepassphrase, [], catch_exceptions=False
1115)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

1116)         assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

1117)         assert result.stderr_bytes is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1118)         assert (
1119)             b'SERVICE is required' in result.stderr_bytes
1120)         ), 'expected error message missing'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

1121) 
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

1122)     def test_226a_no_passphrase_or_key(self, monkeypatch: Any) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1123)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

1124)         with tests.isolated_config(
1125)             monkeypatch=monkeypatch,
1126)             runner=runner,
1127)             config={'services': {}},
1128)         ):
1129)             result = runner.invoke(
1130)                 cli.derivepassphrase, [DUMMY_SERVICE], catch_exceptions=False
1131)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

1132)         assert result.exit_code != 0, 'program unexpectedly succeeded'
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

1133)         assert result.stderr_bytes is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1134)         assert (
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 1 month ago

1135)             b'No passphrase or key given' in result.stderr_bytes
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1136)         ), 'expected error message missing'
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

1137) 
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

1138)     def test_230_config_directory_nonexistant(self, monkeypatch: Any) -> None:
1139)         """the-13th-letter/derivepassphrase#6"""
1140)         runner = click.testing.CliRunner(mix_stderr=False)
1141)         with tests.isolated_config(
1142)             monkeypatch=monkeypatch,
1143)             runner=runner,
1144)             config={'services': {}},
1145)         ):
1146)             os.remove('.derivepassphrase/settings.json')
1147)             os.rmdir('.derivepassphrase')
1148)             os_makedirs_called = False
1149)             real_os_makedirs = os.makedirs
1150) 
1151)             def makedirs(*args: Any, **kwargs: Any) -> Any:
1152)                 nonlocal os_makedirs_called
1153)                 os_makedirs_called = True
1154)                 return real_os_makedirs(*args, **kwargs)
1155) 
1156)             monkeypatch.setattr(os, 'makedirs', makedirs)
1157)             result = runner.invoke(
1158)                 cli.derivepassphrase,
1159)                 ['--config', '-p'],
1160)                 catch_exceptions=False,
1161)                 input='abc\n',
1162)             )
1163)             assert (
1164)                 result.stderr_bytes == b'Passphrase:'
1165)             ), 'program unexpectedly failed?!'
1166)             assert result.exit_code == 0, 'program unexpectedly failed?!'
1167)             assert os_makedirs_called, 'os.makedirs has not been called?!'
1168)             with open(cli._config_filename(), encoding='UTF-8') as infile:
1169)                 config_readback = json.load(infile)
1170)             assert config_readback == {
1171)                 'global': {'phrase': 'abc'},
1172)                 'services': {},
1173)             }, 'config mismatch'
1174) 
1175)     def test_230a_config_directory_not_a_file(self, monkeypatch: Any) -> None:
1176)         """the-13th-letter/derivepassphrase#6"""
1177)         runner = click.testing.CliRunner(mix_stderr=False)
1178)         with tests.isolated_config(
1179)             monkeypatch=monkeypatch,
1180)             runner=runner,
1181)             config={'services': {}},
1182)         ):
1183)             _save_config = cli._save_config
1184) 
1185)             def obstruct_config_saving(*args: Any, **kwargs: Any) -> Any:
1186)                 with contextlib.suppress(FileNotFoundError):
1187)                     shutil.rmtree('.derivepassphrase')
1188)                 with open(
1189)                     '.derivepassphrase', 'w', encoding='UTF-8'
1190)                 ) as outfile:
1191)                     print('Obstruction!!', file=outfile)
1192)                 monkeypatch.setattr(cli, '_save_config', _save_config)
1193)                 return _save_config(*args, **kwargs)
1194) 
1195)             monkeypatch.setattr(cli, '_save_config', obstruct_config_saving)
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 1 month ago

1196)             result = runner.invoke(
1197)                 cli.derivepassphrase,
1198)                 ['--config', '-p'],
1199)                 catch_exceptions=False,
1200)                 input='abc\n',
1201)             )
1202)             assert result.exit_code != 0, 'program unexpectedly succeeded?!'
Marco Ricci Add missing tests for rewor...

Marco Ricci authored 1 month ago

1203)             assert result.stderr_bytes is not None
1204)             assert (
1205)                 b'Cannot store config' in result.stderr_bytes
1206)             ), 'program unexpectedly failed?!'
1207) 
1208)     def test_230b_store_config_custom_error(self, monkeypatch: Any) -> None:
1209)         runner = click.testing.CliRunner(mix_stderr=False)
1210)         with tests.isolated_config(
1211)             monkeypatch=monkeypatch,
1212)             runner=runner,
1213)             config={'services': {}},
1214)         ):
1215)             _save_config = cli._save_config
1216) 
1217)             def obstruct_config_saving(*args: Any, **kwargs: Any) -> Any:
1218)                 with contextlib.suppress(FileNotFoundError):
1219)                     shutil.rmtree('.derivepassphrase')
1220)                 with open(
1221)                     '.derivepassphrase', 'w', encoding='UTF-8'
1222)                 ) as outfile:
1223)                     print('Obstruction!!', file=outfile)
1224)                 monkeypatch.setattr(cli, '_save_config', _save_config)
1225)                 return _save_config(*args, **kwargs)
1226) 
1227)             monkeypatch.setattr(cli, '_save_config', obstruct_config_saving)
1228)             result = runner.invoke(
1229)                 cli.derivepassphrase,
1230)                 ['--config', '-p'],
1231)                 catch_exceptions=False,
1232)                 input='abc\n',
1233)             )
1234)             assert result.exit_code != 0, 'program unexpectedly succeeded?!'
1235)             assert result.stderr_bytes is not None
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 1 month ago

1236)             assert (
1237)                 b'Cannot store config' in result.stderr_bytes
1238)             ), 'program unexpectedly failed?!'
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

1239) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 2 weeks ago

1240)     @pytest.mark.parametrize(
1241)         ['command_line', 'input', 'error_message'],
1242)         [
1243)             pytest.param(
1244)                 ['--import', '-'],
1245)                 json.dumps({
1246)                     'global': {'phrase': 'Du\u0308sseldorf'},
1247)                     'services': {},
1248)                 }),
1249)                 'the global passphrase is not NFC-normalized',
1250)                 id='global-NFC',
1251)             ),
1252)             pytest.param(
1253)                 ['--import', '-'],
1254)                 json.dumps({
1255)                     'services': {
1256)                         DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy(),
1257)                         'weird entry name': {'phrase': 'Du\u0308sseldorf'},
1258)                     }
1259)                 }),
1260)                 (
1261)                     "the services.'weird entry name' passphrase "
1262)                     'is not NFC-normalized'
1263)                 ),
1264)                 id='service-weird-name-NFC',
1265)             ),
1266)             pytest.param(
1267)                 ['--config', '-p', DUMMY_SERVICE],
1268)                 'Du\u0308sseldorf',
1269)                 (
1270)                     f'the services.{DUMMY_SERVICE} passphrase '
1271)                     f'is not NFC-normalized'
1272)                 ),
1273)                 id='config-NFC',
1274)             ),
1275)             pytest.param(
1276)                 ['-p', DUMMY_SERVICE],
1277)                 'Du\u0308sseldorf',
1278)                 'the interactive passphrase is not NFC-normalized',
1279)                 id='direct-input-NFC',
1280)             ),
1281)             pytest.param(
1282)                 ['--import', '-'],
1283)                 json.dumps({
1284)                     'global': {
1285)                         'unicode_normalization_form': 'NFD',
1286)                         'phrase': 'D\u00fcsseldorf',
1287)                     },
1288)                     'services': {},
1289)                 }),
1290)                 'the global passphrase is not NFD-normalized',
1291)                 id='global-NFD',
1292)             ),
1293)             pytest.param(
1294)                 ['--import', '-'],
1295)                 json.dumps({
1296)                     'global': {
1297)                         'unicode_normalization_form': 'NFD',
1298)                     },
1299)                     'services': {
1300)                         DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy(),
1301)                         'weird entry name': {'phrase': 'D\u00fcsseldorf'},
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 weeks ago

1302)                     },
Marco Ricci Allow all textual strings,...

Marco Ricci authored 2 weeks ago

1303)                 }),
1304)                 (
1305)                     "the services.'weird entry name' passphrase "
1306)                     'is not NFD-normalized'
1307)                 ),
1308)                 id='service-weird-name-NFD',
1309)             ),
1310)         ],
1311)     )
1312)     def test_300_unicode_normalization_form_warning(
1313)         self,
1314)         monkeypatch: Any,
1315)         command_line: list[str],
1316)         input: str | None,
1317)         error_message: str,
1318)     ) -> None:
1319)         runner = click.testing.CliRunner(mix_stderr=False)
1320)         with tests.isolated_config(
1321)             monkeypatch=monkeypatch,
1322)             runner=runner,
1323)             config={'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()}},
1324)         ):
1325)             result = runner.invoke(
1326)                 cli.derivepassphrase,
1327)                 command_line,
1328)                 catch_exceptions=False,
1329)                 input=input,
1330)             )
1331)             assert (result.exception, result.exit_code) == (None, 0)
1332)             assert result.stderr_bytes is not None
1333)             assert error_message in result.stderr
1334) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

1336) class TestCLIUtils:
1337)     def test_100_save_bad_config(self, monkeypatch: Any) -> None:
1338)         runner = click.testing.CliRunner()
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

1339)         with (
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1340)             tests.isolated_config(
1341)                 monkeypatch=monkeypatch, runner=runner, config={}
1342)             ),
1343)             pytest.raises(ValueError, match='Invalid vault config'),
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

1344)         ):
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 weeks ago

1345)             cli._save_config(None)  # type: ignore[arg-type]
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1348)         @click.command()
1349)         @click.option('--heading', default='Our menu:')
1350)         @click.argument('items', nargs=-1)
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 1 month ago

1351)         def driver(heading: str, items: list[str]) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1352)             # from https://montypython.fandom.com/wiki/Spam#The_menu
1353)             items = items or [
1354)                 'Egg and bacon',
1355)                 'Egg, sausage and bacon',
1356)                 'Egg and spam',
1357)                 'Egg, bacon and spam',
1358)                 'Egg, bacon, sausage and spam',
1359)                 'Spam, bacon, sausage and spam',
1360)                 'Spam, egg, spam, spam, bacon and spam',
1361)                 'Spam, spam, spam, egg and spam',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1362)                 (
1363)                     'Spam, spam, spam, spam, spam, spam, baked beans, '
1364)                     'spam, spam, spam and spam'
1365)                 ),
1366)                 (
1367)                     'Lobster thermidor aux crevettes with a mornay sauce '
1368)                     'garnished with truffle paté, brandy '
1369)                     'and a fried egg on top and spam'
1370)                 ),
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1371)             ]
1372)             index = cli._prompt_for_selection(items, heading=heading)
1373)             click.echo('A fine choice: ', nl=False)
1374)             click.echo(items[index])
1375)             click.echo('(Note: Vikings strictly optional.)')
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1377)         runner = click.testing.CliRunner(mix_stderr=True)
1378)         result = runner.invoke(driver, [], input='9')
1379)         assert result.exit_code == 0, 'driver program failed'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1380)         assert (
1381)             result.stdout
1382)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1383) Our menu:
1384) [1] Egg and bacon
1385) [2] Egg, sausage and bacon
1386) [3] Egg and spam
1387) [4] Egg, bacon and spam
1388) [5] Egg, bacon, sausage and spam
1389) [6] Spam, bacon, sausage and spam
1390) [7] Spam, egg, spam, spam, bacon and spam
1391) [8] Spam, spam, spam, egg and spam
1392) [9] Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
1393) [10] Lobster thermidor aux crevettes with a mornay sauce garnished with truffle paté, brandy and a fried egg on top and spam
1394) Your selection? (1-10, leave empty to abort): 9
1395) A fine choice: Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
1396) (Note: Vikings strictly optional.)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1397) """  # noqa: E501
1398)         ), 'driver program produced unexpected output'
1399)         result = runner.invoke(
1400)             driver, ['--heading='], input='', catch_exceptions=True
1401)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1402)         assert result.exit_code > 0, 'driver program succeeded?!'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1403)         assert (
1404)             result.stdout
1405)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1406) [1] Egg and bacon
1407) [2] Egg, sausage and bacon
1408) [3] Egg and spam
1409) [4] Egg, bacon and spam
1410) [5] Egg, bacon, sausage and spam
1411) [6] Spam, bacon, sausage and spam
1412) [7] Spam, egg, spam, spam, bacon and spam
1413) [8] Spam, spam, spam, egg and spam
1414) [9] Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
1415) [10] Lobster thermidor aux crevettes with a mornay sauce garnished with truffle paté, brandy and a fried egg on top and spam
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1416) Your selection? (1-10, leave empty to abort):\x20
1417) """  # noqa: E501
1418)         ), 'driver program produced unexpected output'
1419)         assert isinstance(
1420)             result.exception, IndexError
1421)         ), 'driver program did not raise IndexError?!'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1424)         @click.command()
1425)         @click.option('--item', default='baked beans')
1426)         @click.argument('prompt')
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 1 month ago

1427)         def driver(item: str, prompt: str) -> None:
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1428)             try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1429)                 cli._prompt_for_selection(
1430)                     [item], heading='', single_choice_prompt=prompt
1431)                 )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1435)             else:
1436)                 click.echo('Great!')
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1438)         runner = click.testing.CliRunner(mix_stderr=True)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1442)         assert result.exit_code == 0, 'driver program failed'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1443)         assert (
1444)             result.stdout
1445)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1446) [1] baked beans
1447) Will replace with spam. Confirm, y/n? y
1448) Great!
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1449) """
1450)         ), 'driver program produced unexpected output'
1451)         result = runner.invoke(
1452)             driver,
1453)             ['Will replace with spam, okay? ' '(Please say "y" or "n".)'],
1454)             input='',
1455)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1456)         assert result.exit_code > 0, 'driver program succeeded?!'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1457)         assert (
1458)             result.stdout
1459)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1460) [1] baked beans
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1462) Boo.
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1463) """
1464)         ), 'driver program produced unexpected output'
1465)         assert isinstance(
1466)             result.exception, IndexError
1467)         ), 'driver program did not raise IndexError?!'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1468) 
1469)     def test_103_prompt_for_passphrase(self, monkeypatch: Any) -> None:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1470)         monkeypatch.setattr(
1471)             click,
1472)             'prompt',
1473)             lambda *a, **kw: json.dumps({'args': a, 'kwargs': kw}),
1474)         )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1476)         err_msg = 'missing arguments to passphrase prompt'
1477)         assert 'args' in res, err_msg
1478)         assert 'kwargs' in res, err_msg
1479)         assert res['args'][:1] == ['Passphrase'], err_msg
1480)         assert res['kwargs'].get('default') == '', err_msg
1481)         assert not res['kwargs'].get('show_default', True), err_msg
1482)         assert res['kwargs'].get('err'), err_msg
1483)         assert res['kwargs'].get('hide_input'), err_msg
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1484) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1485)     @pytest.mark.parametrize(
1486)         ['command_line', 'config', 'result_config'],
1487)         [
1488)             (
1489)                 ['--delete-globals'],
1490)                 {'global': {'phrase': 'abc'}, 'services': {}},
1491)                 {'services': {}},
1492)             ),
1493)             (
1494)                 ['--delete', DUMMY_SERVICE],
1495)                 {
1496)                     'global': {'phrase': 'abc'},
1497)                     'services': {DUMMY_SERVICE: {'notes': '...'}},
1498)                 },
1499)                 {'global': {'phrase': 'abc'}, 'services': {}},
1500)             ),
1501)             (
1502)                 ['--clear'],
1503)                 {
1504)                     'global': {'phrase': 'abc'},
1505)                     'services': {DUMMY_SERVICE: {'notes': '...'}},
1506)                 },
1507)                 {'services': {}},
1508)             ),
1509)         ],
1510)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1511)     def test_203_repeated_config_deletion(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1512)         self,
1513)         monkeypatch: Any,
1514)         command_line: list[str],
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 1 month ago

1515)         config: _types.VaultConfig,
1516)         result_config: _types.VaultConfig,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1517)     ) -> None:
1518)         runner = click.testing.CliRunner(mix_stderr=False)
1519)         for start_config in [config, result_config]:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1520)             with tests.isolated_config(
1521)                 monkeypatch=monkeypatch, runner=runner, config=start_config
1522)             ):
1523)                 result = runner.invoke(
1524)                     cli.derivepassphrase, command_line, catch_exceptions=False
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1525)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1526)                 assert (result.exit_code, result.stderr_bytes) == (
1527)                     0,
1528)                     b'',
1529)                 ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1531)                     config_readback = json.load(infile)
1532)                 assert config_readback == result_config
1533) 
1534)     def test_204_phrase_from_key_manually(self) -> None:
1535)         assert (
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

1536)             dpp.vault.Vault(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1537)                 phrase=DUMMY_PHRASE_FROM_KEY1, **DUMMY_CONFIG_SETTINGS
1538)             ).generate(DUMMY_SERVICE)
1539)             == DUMMY_RESULT_KEY1
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1540)         )
1541) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1542)     @pytest.mark.parametrize(
1543)         ['vfunc', 'input'],
1544)         [
1545)             (cli._validate_occurrence_constraint, 20),
1546)             (cli._validate_length, 20),
1547)         ],
1548)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1549)     def test_210a_validate_constraints_manually(
1550)         self,
1551)         vfunc: Callable[[click.Context, click.Parameter, Any], int | None],
1552)         input: int,
1553)     ) -> None:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1555)         param = cli.derivepassphrase.params[0]
1556)         assert vfunc(ctx, param, input) == input
1557) 
1558)     @tests.skip_if_no_agent
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1560)     def test_227_get_suitable_ssh_keys(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1561)         self,
1562)         monkeypatch: Any,
1563)         conn_hint: str,
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

1564)     ) -> None:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1565)         monkeypatch.setattr(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

1566)             ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1567)         )
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

1568)         hint: ssh_agent.SSHAgentClient | socket.socket | None
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1569)         match conn_hint:
1570)             case 'client':
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

1571)                 hint = ssh_agent.SSHAgentClient()
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1572)             case 'socket':
1573)                 hint = socket.socket(family=socket.AF_UNIX)
1574)                 hint.connect(os.environ['SSH_AUTH_SOCK'])
1575)             case _:
1576)                 assert conn_hint == 'none'
1577)                 hint = None
1578)         exception: Exception | None = None
1579)         try:
1580)             list(cli._get_suitable_ssh_keys(hint))
1581)         except RuntimeError:  # pragma: no cover
1582)             pass
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1584)             exception = e
1585)         finally: