abadc0d0b8f8e910d31073a0dfcd8e82509daab6
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 Remove `click` handling of...

Marco Ricci authored 2 weeks ago

8) import errno
Marco Ricci Add finished command-line i...

Marco Ricci authored 2 months ago

9) import json
10) import os
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

28) DUMMY_SERVICE = tests.DUMMY_SERVICE
29) DUMMY_PASSPHRASE = tests.DUMMY_PASSPHRASE
30) DUMMY_CONFIG_SETTINGS = tests.DUMMY_CONFIG_SETTINGS
31) DUMMY_RESULT_PASSPHRASE = tests.DUMMY_RESULT_PASSPHRASE
32) DUMMY_RESULT_KEY1 = tests.DUMMY_RESULT_KEY1
33) DUMMY_PHRASE_FROM_KEY1_RAW = tests.DUMMY_PHRASE_FROM_KEY1_RAW
34) DUMMY_PHRASE_FROM_KEY1 = tests.DUMMY_PHRASE_FROM_KEY1
35) 
36) DUMMY_KEY1 = tests.DUMMY_KEY1
37) DUMMY_KEY1_B64 = tests.DUMMY_KEY1_B64
38) DUMMY_KEY2 = tests.DUMMY_KEY2
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

88) ]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

220) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

280) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

309)     def test_204a_key_from_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

320)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

363) 
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

425)     def test_205_service_phrase_if_key_in_global_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

444)         ):
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

457) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

533)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

537)             else:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

542)         if check_success:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

556)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

570)     def test_212_incompatible_options(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

594)     def test_213_import_bad_config_not_vault_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

607)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

616)     def test_213a_import_bad_config_not_json_data(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

629)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

638)     def test_213b_import_bad_config_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

658)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

659)             assert result.exit_code > 0, 'program unexpectedly succeeded'
660)             assert (
661)                 result.stderr_bytes
662)             ), 'program did not print any error message'
Marco Ricci Remove `click` handling of...

Marco Ricci authored 2 weeks ago

663)             assert (
664)                 os.strerror(errno.EISDIR).encode('utf-8')
665)                 in result.stderr_bytes
666)             ), 'program did not print the expected error message'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

667) 
668)     def test_214_export_settings_no_stored_settings(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

669)         self,
670)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

680)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

686)     def test_214a_export_settings_bad_stored_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

687)         self,
688)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

699)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

708)     def test_214b_export_settings_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

709)         self,
710)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

717)                 os.remove(cli._config_filename())
718)             os.makedirs(cli._config_filename())
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

724)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

733)     def test_214c_export_settings_target_not_a_file(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

734)         self,
735)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

738)         with tests.isolated_config(
739)             monkeypatch=monkeypatch, runner=runner, config={'services': {}}
740)         ):
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

747)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

755) 
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

784) 
785) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
786) contents go here
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

797)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

798)             assert (result.exit_code, result.stderr_bytes) == (
799)                 0,
800)                 b'',
801)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

819)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

820)             assert (result.exit_code, result.stderr_bytes) == (
821)                 0,
822)                 b'',
823)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

838)             )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

839)             assert (result.exit_code, result.stderr_bytes) == (
840)                 0,
841)                 b'',
842)             ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

909)     def test_224_store_config_good(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

910)         self,
911)         monkeypatch: Any,
912)         command_line: list[str],
913)         input: bytes,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

914)         result_config: Any,
915)     ) -> None:
916)         runner = click.testing.CliRunner(mix_stderr=False)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

934)             assert (
935)                 config == result_config
936)             ), 'stored config does not match expectation'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

937) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

945)             ),
946)             (
947)                 ['sv'],
948)                 b'',
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

953)         ],
954)     )
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

955)     def test_225_store_config_fail(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

979)             assert (
980)                 err_text in result.stderr_bytes
981)             ), 'expected error message missing'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

982) 
983)     def test_225a_store_config_fail_manual_no_ssh_key_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

984)         self,
985)         monkeypatch: Any,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1006)             assert (
1007)                 custom_error.encode() in result.stderr_bytes
1008)             ), 'expected error message missing'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1124) 
Marco Ricci Isolate tests properly and...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1140) 
Marco Ricci Create the configuration di...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1342)         with (
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1383)         assert (
1384)             result.stdout
1385)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1406)         assert (
1407)             result.stdout
1408)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1409) [1] Egg and bacon
1410) [2] Egg, sausage and bacon
1411) [3] Egg and spam
1412) [4] Egg, bacon and spam
1413) [5] Egg, bacon, sausage and spam
1414) [6] Spam, bacon, sausage and spam
1415) [7] Spam, egg, spam, spam, bacon and spam
1416) [8] Spam, spam, spam, egg and spam
1417) [9] Spam, spam, spam, spam, spam, spam, baked beans, spam, spam, spam and spam
1418) [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

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1431)             try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1432)                 cli._prompt_for_selection(
1433)                     [item], heading='', single_choice_prompt=prompt
1434)                 )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1446)         assert (
1447)             result.stdout
1448)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

1460)         assert (
1461)             result.stdout
1462)             == """\
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1465) Boo.
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1487) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1514)     def test_203_repeated_config_deletion(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1515)         self,
1516)         monkeypatch: Any,
1517)         command_line: list[str],
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 1 month ago

1518)         config: _types.VaultConfig,
1519)         result_config: _types.VaultConfig,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1528)                 )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1529)                 assert (result.exit_code, result.stderr_bytes) == (
1530)                     0,
1531)                     b'',
1532)                 ), 'program exited with failure'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

1540)                 phrase=DUMMY_PHRASE_FROM_KEY1, **DUMMY_CONFIG_SETTINGS
1541)             ).generate(DUMMY_SERVICE)
1542)             == DUMMY_RESULT_KEY1
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1543)         )
1544) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1563)     def test_227_get_suitable_ssh_keys(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 1 month ago

1564)         self,
1565)         monkeypatch: Any,
1566)         conn_hint: str,
Marco Ricci Fix miscellaneous type chec...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1572)         match conn_hint:
1573)             case 'client':
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 months ago

1587)             exception = e
1588)         finally: