Marco Ricci commited on 2025-01-27 19:46:57
Zeige 1 geänderte Dateien mit 79 Einfügungen und 88 Löschungen.
Reformat the "vault" tests. This includes retiring the `Vault` type alias and using the proper Google-style `vault.Vault` instead, because the API documentation does not correctly resolve this type alias otherwise.
... | ... |
@@ -13,16 +13,14 @@ from typing import TYPE_CHECKING |
13 | 13 |
import hypothesis |
14 | 14 |
import pytest |
15 | 15 |
from hypothesis import strategies |
16 |
-from typing_extensions import TypeAlias, TypeVar |
|
16 |
+from typing_extensions import TypeVar |
|
17 | 17 |
|
18 |
-import derivepassphrase |
|
19 | 18 |
import tests |
19 |
+from derivepassphrase import vault |
|
20 | 20 |
|
21 | 21 |
if TYPE_CHECKING: |
22 | 22 |
from collections.abc import Iterator |
23 | 23 |
|
24 |
-Vault: TypeAlias = derivepassphrase.vault.Vault |
|
25 |
- |
|
26 | 24 |
BLOCK_SIZE = hashlib.sha1().block_size |
27 | 25 |
DIGEST_SIZE = hashlib.sha1().digest_size |
28 | 26 |
|
... | ... |
@@ -32,7 +30,7 @@ def phrases_are_interchangable( |
32 | 30 |
phrase2: bytes | bytearray | str, |
33 | 31 |
/, |
34 | 32 |
) -> bool: |
35 |
- """Work-alike of [`Vault.phrases_are_interchangable`][]. |
|
33 |
+ """Work-alike of [`vault.Vault.phrases_are_interchangable`][]. |
|
36 | 34 |
|
37 | 35 |
This version is not resistant to timing attacks, but faster, and |
38 | 36 |
supports strings directly. |
... | ... |
@@ -44,7 +42,7 @@ def phrases_are_interchangable( |
44 | 42 |
A passphrase to compare. |
45 | 43 |
|
46 | 44 |
Returns: |
47 |
- True if the phrases behave identically under [`Vault`][], |
|
45 |
+ True if the phrases behave identically under [`vault.Vault`][], |
|
48 | 46 |
false otherwise. |
49 | 47 |
|
50 | 48 |
""" |
... | ... |
@@ -56,8 +54,8 @@ def phrases_are_interchangable( |
56 | 54 |
else bs.rstrip(b'\x00') |
57 | 55 |
) |
58 | 56 |
|
59 |
- phrase1 = canon(Vault._get_binary_string(phrase1)) |
|
60 |
- phrase2 = canon(Vault._get_binary_string(phrase2)) |
|
57 |
+ phrase1 = canon(vault.Vault._get_binary_string(phrase1)) |
|
58 |
+ phrase2 = canon(vault.Vault._get_binary_string(phrase2)) |
|
61 | 59 |
return phrase1 == phrase2 |
62 | 60 |
|
63 | 61 |
|
... | ... |
@@ -83,9 +81,7 @@ class TestVault: |
83 | 81 |
min_size=2, |
84 | 82 |
max_size=2, |
85 | 83 |
unique=True, |
86 |
- ).filter( |
|
87 |
- lambda tup: not phrases_are_interchangable(*tup) |
|
88 |
- ), |
|
84 |
+ ).filter(lambda tup: not phrases_are_interchangable(*tup)), |
|
89 | 85 |
service=strategies.text( |
90 | 86 |
strategies.characters(min_codepoint=32, max_codepoint=126), |
91 | 87 |
min_size=1, |
... | ... |
@@ -102,9 +98,9 @@ class TestVault: |
102 | 98 |
We filter out interchangable passphrases during generation. |
103 | 99 |
|
104 | 100 |
""" |
105 |
- assert Vault.create_hash( |
|
101 |
+ assert vault.Vault.create_hash( |
|
106 | 102 |
phrase=phrases[0], service=service |
107 |
- ) != Vault.create_hash(phrase=phrases[1], service=service) |
|
103 |
+ ) != vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
108 | 104 |
|
109 | 105 |
@hypothesis.given( |
110 | 106 |
phrases=strategies.lists( |
... | ... |
@@ -112,9 +108,7 @@ class TestVault: |
112 | 108 |
min_size=2, |
113 | 109 |
max_size=2, |
114 | 110 |
unique=True, |
115 |
- ).filter( |
|
116 |
- lambda tup: not phrases_are_interchangable(*tup) |
|
117 |
- ), |
|
111 |
+ ).filter(lambda tup: not phrases_are_interchangable(*tup)), |
|
118 | 112 |
service=strategies.text( |
119 | 113 |
strategies.characters(min_codepoint=32, max_codepoint=126), |
120 | 114 |
min_size=1, |
... | ... |
@@ -131,9 +125,9 @@ class TestVault: |
131 | 125 |
We filter out interchangable passphrases during generation. |
132 | 126 |
|
133 | 127 |
""" |
134 |
- assert Vault.create_hash( |
|
128 |
+ assert vault.Vault.create_hash( |
|
135 | 129 |
phrase=phrases[0], service=service |
136 |
- ) != Vault.create_hash(phrase=phrases[1], service=service) |
|
130 |
+ ) != vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
137 | 131 |
|
138 | 132 |
@hypothesis.given( |
139 | 133 |
phrases=strategies.lists( |
... | ... |
@@ -143,9 +137,7 @@ class TestVault: |
143 | 137 |
min_size=2, |
144 | 138 |
max_size=2, |
145 | 139 |
unique=True, |
146 |
- ).filter( |
|
147 |
- lambda tup: not phrases_are_interchangable(*tup) |
|
148 |
- ), |
|
140 |
+ ).filter(lambda tup: not phrases_are_interchangable(*tup)), |
|
149 | 141 |
service=strategies.text( |
150 | 142 |
strategies.characters(min_codepoint=32, max_codepoint=126), |
151 | 143 |
min_size=1, |
... | ... |
@@ -162,9 +154,9 @@ class TestVault: |
162 | 154 |
We filter out interchangable passphrases during generation. |
163 | 155 |
|
164 | 156 |
""" |
165 |
- assert Vault.create_hash( |
|
157 |
+ assert vault.Vault.create_hash( |
|
166 | 158 |
phrase=phrases[0], service=service |
167 |
- ) != Vault.create_hash(phrase=phrases[1], service=service) |
|
159 |
+ ) != vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
168 | 160 |
|
169 | 161 |
@hypothesis.given( |
170 | 162 |
phrases=strategies.lists( |
... | ... |
@@ -178,9 +170,7 @@ class TestVault: |
178 | 170 |
min_size=2, |
179 | 171 |
max_size=2, |
180 | 172 |
unique=True, |
181 |
- ).filter( |
|
182 |
- lambda tup: not phrases_are_interchangable(*tup) |
|
183 |
- ), |
|
173 |
+ ).filter(lambda tup: not phrases_are_interchangable(*tup)), |
|
184 | 174 |
service=strategies.text( |
185 | 175 |
strategies.characters(min_codepoint=32, max_codepoint=126), |
186 | 176 |
min_size=1, |
... | ... |
@@ -197,9 +187,9 @@ class TestVault: |
197 | 187 |
We filter out interchangable passphrases during generation. |
198 | 188 |
|
199 | 189 |
""" |
200 |
- assert Vault.create_hash( |
|
190 |
+ assert vault.Vault.create_hash( |
|
201 | 191 |
phrase=phrases[0], service=service |
202 |
- ) != Vault.create_hash(phrase=phrases[1], service=service) |
|
192 |
+ ) != vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
203 | 193 |
|
204 | 194 |
@hypothesis.given( |
205 | 195 |
phrase=strategies.text( |
... | ... |
@@ -220,9 +210,9 @@ class TestVault: |
220 | 210 |
services: list[bytes], |
221 | 211 |
) -> None: |
222 | 212 |
"""The internal hash is dependent on the service name.""" |
223 |
- assert Vault.create_hash( |
|
213 |
+ assert vault.Vault.create_hash( |
|
224 | 214 |
phrase=phrase, service=services[0] |
225 |
- ) != Vault.create_hash(phrase=phrase, service=services[1]) |
|
215 |
+ ) != vault.Vault.create_hash(phrase=phrase, service=services[1]) |
|
226 | 216 |
|
227 | 217 |
@tests.hypothesis_settings_coverage_compatible |
228 | 218 |
@hypothesis.given( |
... | ... |
@@ -232,7 +222,7 @@ class TestVault: |
232 | 222 |
strategies.integers( |
233 | 223 |
min_value=1, |
234 | 224 |
max_value=BLOCK_SIZE - len(bs), |
235 |
- ).map(lambda num: bs + b'\x00' * num) |
|
225 |
+ ).map(lambda num: bs + b'\x00' * num), |
|
236 | 226 |
) |
237 | 227 |
), |
238 | 228 |
service=strategies.text( |
... | ... |
@@ -247,10 +237,10 @@ class TestVault: |
247 | 237 |
service: str, |
248 | 238 |
) -> None: |
249 | 239 |
"""Claimed interchangable passphrases are actually interchangable.""" |
250 |
- assert Vault.phrases_are_interchangable(*phrases) |
|
251 |
- assert Vault.create_hash( |
|
240 |
+ assert vault.Vault.phrases_are_interchangable(*phrases) |
|
241 |
+ assert vault.Vault.create_hash( |
|
252 | 242 |
phrase=phrases[0], service=service |
253 |
- ) == Vault.create_hash(phrase=phrases[1], service=service) |
|
243 |
+ ) == vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
254 | 244 |
|
255 | 245 |
@tests.hypothesis_settings_coverage_compatible |
256 | 246 |
@hypothesis.given( |
... | ... |
@@ -279,10 +269,10 @@ class TestVault: |
279 | 269 |
service: str, |
280 | 270 |
) -> None: |
281 | 271 |
"""Claimed interchangable passphrases are actually interchangable.""" |
282 |
- assert Vault.phrases_are_interchangable(*phrases) |
|
283 |
- assert Vault.create_hash( |
|
272 |
+ assert vault.Vault.phrases_are_interchangable(*phrases) |
|
273 |
+ assert vault.Vault.create_hash( |
|
284 | 274 |
phrase=phrases[0], service=service |
285 |
- ) == Vault.create_hash(phrase=phrases[1], service=service) |
|
275 |
+ ) == vault.Vault.create_hash(phrase=phrases[1], service=service) |
|
286 | 276 |
|
287 | 277 |
@pytest.mark.parametrize( |
288 | 278 |
['service', 'expected'], |
... | ... |
@@ -295,12 +285,12 @@ class TestVault: |
295 | 285 |
self, service: bytes | str, expected: bytes |
296 | 286 |
) -> None: |
297 | 287 |
"""Deriving a passphrase principally works.""" |
298 |
- assert Vault(phrase=self.phrase).generate(service) == expected |
|
288 |
+ assert vault.Vault(phrase=self.phrase).generate(service) == expected |
|
299 | 289 |
|
300 | 290 |
def test_201_phrase_dependence(self) -> None: |
301 | 291 |
"""The derived passphrase is dependent on the master passphrase.""" |
302 | 292 |
assert ( |
303 |
- Vault(phrase=(self.phrase + b'X')).generate('google') |
|
293 |
+ vault.Vault(phrase=(self.phrase + b'X')).generate('google') |
|
304 | 294 |
== b'n+oIz6sL>K*lTEWYRO%7' |
305 | 295 |
) |
306 | 296 |
|
... | ... |
@@ -310,9 +300,7 @@ class TestVault: |
310 | 300 |
min_size=2, |
311 | 301 |
max_size=2, |
312 | 302 |
unique=True, |
313 |
- ).filter( |
|
314 |
- lambda tup: not phrases_are_interchangable(*tup) |
|
315 |
- ), |
|
303 |
+ ).filter(lambda tup: not phrases_are_interchangable(*tup)), |
|
316 | 304 |
service=strategies.text( |
317 | 305 |
strategies.characters(min_codepoint=32, max_codepoint=126), |
318 | 306 |
min_size=1, |
... | ... |
@@ -348,27 +336,27 @@ class TestVault: |
348 | 336 |
"""The derived passphrase is dependent on the master passphrase. |
349 | 337 |
|
350 | 338 |
Certain pairs of master passphrases are known to be |
351 |
- interchangable; see [`Vault.phrases_are_interchangable`][]. |
|
339 |
+ interchangable; see [`vault.Vault.phrases_are_interchangable`][]. |
|
352 | 340 |
These are excluded from consideration by the hypothesis |
353 | 341 |
strategy. |
354 | 342 |
|
355 | 343 |
""" |
356 | 344 |
# See test_100_create_hash_phrase_dependence for context. |
357 |
- assert Vault(phrase=phrases[0]).generate( |
|
358 |
- service |
|
359 |
- ) != Vault(phrase=phrases[1]).generate(service) |
|
345 |
+ assert vault.Vault(phrase=phrases[0]).generate(service) != vault.Vault( |
|
346 |
+ phrase=phrases[1] |
|
347 |
+ ).generate(service) |
|
360 | 348 |
|
361 | 349 |
def test_202a_reproducibility_and_bytes_service_name(self) -> None: |
362 | 350 |
"""Deriving a passphrase works equally for byte strings.""" |
363 |
- assert Vault(phrase=self.phrase).generate(b'google') == Vault( |
|
364 |
- phrase=self.phrase |
|
365 |
- ).generate('google') |
|
351 |
+ assert vault.Vault(phrase=self.phrase).generate( |
|
352 |
+ b'google' |
|
353 |
+ ) == vault.Vault(phrase=self.phrase).generate('google') |
|
366 | 354 |
|
367 | 355 |
def test_202b_reproducibility_and_bytearray_service_name(self) -> None: |
368 | 356 |
"""Deriving a passphrase works equally for byte arrays.""" |
369 |
- assert Vault(phrase=self.phrase).generate(b'google') == Vault( |
|
370 |
- phrase=self.phrase |
|
371 |
- ).generate(bytearray(b'google')) |
|
357 |
+ assert vault.Vault(phrase=self.phrase).generate( |
|
358 |
+ b'google' |
|
359 |
+ ) == vault.Vault(phrase=self.phrase).generate(bytearray(b'google')) |
|
372 | 360 |
|
373 | 361 |
@hypothesis.given( |
374 | 362 |
phrase=strategies.text( |
... | ... |
@@ -388,10 +376,10 @@ class TestVault: |
388 | 376 |
service: str, |
389 | 377 |
) -> None: |
390 | 378 |
"""Deriving a passphrase works equally for byte arrays/strings.""" |
391 |
- assert Vault(phrase=phrase).generate(service) == Vault( |
|
379 |
+ assert vault.Vault(phrase=phrase).generate(service) == vault.Vault( |
|
392 | 380 |
phrase=phrase |
393 | 381 |
).generate(service.encode('utf-8')) |
394 |
- assert Vault(phrase=phrase).generate(service) == Vault( |
|
382 |
+ assert vault.Vault(phrase=phrase).generate(service) == vault.Vault( |
|
395 | 383 |
phrase=phrase |
396 | 384 |
).generate(bytearray(service.encode('utf-8'))) |
397 | 385 |
|
... | ... |
@@ -414,9 +402,9 @@ class TestVault: |
414 | 402 |
services: list[bytes], |
415 | 403 |
) -> None: |
416 | 404 |
"""The derived passphrase is dependent on the service name.""" |
417 |
- assert Vault(phrase=phrase).generate( |
|
418 |
- services[0] |
|
419 |
- ) != Vault(phrase=phrase).generate(services[1]) |
|
405 |
+ assert vault.Vault(phrase=phrase).generate(services[0]) != vault.Vault( |
|
406 |
+ phrase=phrase |
|
407 |
+ ).generate(services[1]) |
|
420 | 408 |
|
421 | 409 |
@tests.hypothesis_settings_coverage_compatible |
422 | 410 |
@hypothesis.given( |
... | ... |
@@ -441,9 +429,9 @@ class TestVault: |
441 | 429 |
) -> None: |
442 | 430 |
"""The derived passphrase is dependent on the service name.""" |
443 | 431 |
try: |
444 |
- assert Vault(phrase=phrase, **config).generate( |
|
432 |
+ assert vault.Vault(phrase=phrase, **config).generate( |
|
445 | 433 |
services[0] |
446 |
- ) != Vault(phrase=phrase, **config).generate(services[1]) |
|
434 |
+ ) != vault.Vault(phrase=phrase, **config).generate(services[1]) |
|
447 | 435 |
except ValueError as exc: |
448 | 436 |
# The service configuration strategy attempts to only |
449 | 437 |
# generate satisfiable configurations. It is possible, |
... | ... |
@@ -458,7 +446,8 @@ class TestVault: |
458 | 446 |
def test_210_nonstandard_length(self) -> None: |
459 | 447 |
"""Deriving a passphrase adheres to imposed length limits.""" |
460 | 448 |
assert ( |
461 |
- Vault(phrase=self.phrase, length=4).generate('google') == b'xDFu' |
|
449 |
+ vault.Vault(phrase=self.phrase, length=4).generate('google') |
|
450 |
+ == b'xDFu' |
|
462 | 451 |
) |
463 | 452 |
|
464 | 453 |
@tests.hypothesis_settings_coverage_compatible |
... | ... |
@@ -481,13 +470,13 @@ class TestVault: |
481 | 470 |
service: str, |
482 | 471 |
) -> None: |
483 | 472 |
"""Derived passphrases have the requested length.""" |
484 |
- password = Vault(phrase=phrase, length=length).generate(service) |
|
473 |
+ password = vault.Vault(phrase=phrase, length=length).generate(service) |
|
485 | 474 |
assert len(password) == length |
486 | 475 |
|
487 | 476 |
def test_211_repetition_limit(self) -> None: |
488 | 477 |
"""Deriving a passphrase adheres to imposed repetition limits.""" |
489 | 478 |
assert ( |
490 |
- Vault( |
|
479 |
+ vault.Vault( |
|
491 | 480 |
phrase=b'', length=24, symbol=0, number=0, repeat=1 |
492 | 481 |
).generate('asd') |
493 | 482 |
== b'IVTDzACftqopUXqDHPkuCIhV' |
... | ... |
@@ -496,14 +485,14 @@ class TestVault: |
496 | 485 |
def test_212_without_symbols(self) -> None: |
497 | 486 |
"""Deriving a passphrase adheres to imposed limits on symbols.""" |
498 | 487 |
assert ( |
499 |
- Vault(phrase=self.phrase, symbol=0).generate('google') |
|
488 |
+ vault.Vault(phrase=self.phrase, symbol=0).generate('google') |
|
500 | 489 |
== b'XZ4wRe0bZCazbljCaMqR' |
501 | 490 |
) |
502 | 491 |
|
503 | 492 |
def test_213_no_numbers(self) -> None: |
504 | 493 |
"""Deriving a passphrase adheres to imposed limits on numbers.""" |
505 | 494 |
assert ( |
506 |
- Vault(phrase=self.phrase, number=0).generate('google') |
|
495 |
+ vault.Vault(phrase=self.phrase, number=0).generate('google') |
|
507 | 496 |
== b'_*$TVH.%^aZl(LUeOT?>' |
508 | 497 |
) |
509 | 498 |
|
... | ... |
@@ -512,28 +501,30 @@ class TestVault: |
512 | 501 |
Deriving a passphrase adheres to imposed limits on lowercase letters. |
513 | 502 |
""" |
514 | 503 |
assert ( |
515 |
- Vault(phrase=self.phrase, lower=0).generate('google') |
|
504 |
+ vault.Vault(phrase=self.phrase, lower=0).generate('google') |
|
516 | 505 |
== b':{?)+7~@OA:L]!0E$)(+' |
517 | 506 |
) |
518 | 507 |
|
519 | 508 |
def test_215_at_least_5_digits(self) -> None: |
520 | 509 |
"""Deriving a passphrase adheres to imposed counts of numbers.""" |
521 | 510 |
assert ( |
522 |
- Vault(phrase=self.phrase, length=8, number=5).generate('songkick') |
|
511 |
+ vault.Vault(phrase=self.phrase, length=8, number=5).generate( |
|
512 |
+ 'songkick' |
|
513 |
+ ) |
|
523 | 514 |
== b'i0908.7[' |
524 | 515 |
) |
525 | 516 |
|
526 | 517 |
def test_216_lots_of_spaces(self) -> None: |
527 | 518 |
"""Deriving a passphrase adheres to imposed counts of spaces.""" |
528 | 519 |
assert ( |
529 |
- Vault(phrase=self.phrase, space=12).generate('songkick') |
|
520 |
+ vault.Vault(phrase=self.phrase, space=12).generate('songkick') |
|
530 | 521 |
== b' c 6 Bq % 5fR ' |
531 | 522 |
) |
532 | 523 |
|
533 | 524 |
def test_217_all_character_classes(self) -> None: |
534 | 525 |
"""Deriving a passphrase adheres to imposed counts of all types.""" |
535 | 526 |
assert ( |
536 |
- Vault( |
|
527 |
+ vault.Vault( |
|
537 | 528 |
phrase=self.phrase, |
538 | 529 |
lower=2, |
539 | 530 |
upper=2, |
... | ... |
@@ -603,7 +594,7 @@ class TestVault: |
603 | 594 |
) -> None: |
604 | 595 |
"""Derived passphrases obey character and occurrence restraints.""" |
605 | 596 |
try: |
606 |
- password = Vault(phrase=phrase, **config).generate(service) |
|
597 |
+ password = vault.Vault(phrase=phrase, **config).generate(service) |
|
607 | 598 |
except ValueError as exc: |
608 | 599 |
# The service configuration strategy attempts to only |
609 | 600 |
# generate satisfiable configurations. It is possible, |
... | ... |
@@ -619,7 +610,7 @@ class TestVault: |
619 | 610 |
for key in ('lower', 'upper', 'number', 'space', 'dash', 'symbol'): |
620 | 611 |
if config[key] > 0: |
621 | 612 |
assert ( |
622 |
- sum(c in Vault._CHARSETS[key] for c in password) |
|
613 |
+ sum(c in vault.Vault._CHARSETS[key] for c in password) |
|
623 | 614 |
>= config[key] |
624 | 615 |
), ( |
625 | 616 |
'Password does not satisfy ' |
... | ... |
@@ -630,9 +621,9 @@ class TestVault: |
630 | 621 |
# appear via the other character class. |
631 | 622 |
assert True |
632 | 623 |
else: |
633 |
- assert sum(c in Vault._CHARSETS[key] for c in password) == 0, ( |
|
634 |
- 'Password does not satisfy character ban constraints.' |
|
635 |
- ) |
|
624 |
+ assert ( |
|
625 |
+ sum(c in vault.Vault._CHARSETS[key] for c in password) == 0 |
|
626 |
+ ), 'Password does not satisfy character ban constraints.' |
|
636 | 627 |
|
637 | 628 |
T = TypeVar('T', str, bytes) |
638 | 629 |
|
... | ... |
@@ -653,7 +644,7 @@ class TestVault: |
653 | 644 |
This example is checked explicitly against forbidden substrings. |
654 | 645 |
|
655 | 646 |
""" |
656 |
- generated = Vault( |
|
647 |
+ generated = vault.Vault( |
|
657 | 648 |
phrase=b'', |
658 | 649 |
length=40, |
659 | 650 |
lower=0, |
... | ... |
@@ -702,22 +693,22 @@ class TestVault: |
702 | 693 |
service: str, |
703 | 694 |
) -> None: |
704 | 695 |
"""Derived passphrases obey the given occurrence constraint.""" |
705 |
- password = Vault(phrase=phrase, length=length, repeat=repeat).generate( |
|
706 |
- service |
|
707 |
- ) |
|
696 |
+ password = vault.Vault( |
|
697 |
+ phrase=phrase, length=length, repeat=repeat |
|
698 |
+ ).generate(service) |
|
708 | 699 |
for i in range((length + 1) - (repeat + 1)): |
709 | 700 |
assert len(set(password[i : i + repeat + 1])) > 1 |
710 | 701 |
|
711 | 702 |
def test_219_very_limited_character_set(self) -> None: |
712 | 703 |
"""Deriving a passphrase works even with limited character sets.""" |
713 |
- generated = Vault( |
|
704 |
+ generated = vault.Vault( |
|
714 | 705 |
phrase=b'', length=24, lower=0, upper=0, space=0, symbol=0 |
715 | 706 |
).generate('testing') |
716 | 707 |
assert generated == b'763252593304946694588866' |
717 | 708 |
|
718 | 709 |
def test_220_character_set_subtraction(self) -> None: |
719 | 710 |
"""Removing allowed characters internally works.""" |
720 |
- assert Vault._subtract(b'be', b'abcdef') == bytearray(b'acdf') |
|
711 |
+ assert vault.Vault._subtract(b'be', b'abcdef') == bytearray(b'acdf') |
|
721 | 712 |
|
722 | 713 |
@pytest.mark.parametrize( |
723 | 714 |
['length', 'settings', 'entropy'], |
... | ... |
@@ -742,7 +733,7 @@ class TestVault: |
742 | 733 |
self, length: int, settings: dict[str, int], entropy: int |
743 | 734 |
) -> None: |
744 | 735 |
"""Estimating the entropy and sufficient hash length works.""" |
745 |
- v = Vault(length=length, **settings) # type: ignore[arg-type] |
|
736 |
+ v = vault.Vault(length=length, **settings) # type: ignore[arg-type] |
|
746 | 737 |
assert math.isclose(v._entropy(), entropy) |
747 | 738 |
assert v._estimate_sufficient_hash_length() > 0 |
748 | 739 |
if math.isfinite(entropy) and entropy: |
... | ... |
@@ -755,7 +746,7 @@ class TestVault: |
755 | 746 |
""" |
756 | 747 |
Estimating the entropy and hash length for degenerate cases works. |
757 | 748 |
""" |
758 |
- v = Vault( |
|
749 |
+ v = vault.Vault( |
|
759 | 750 |
phrase=self.phrase, |
760 | 751 |
lower=0, |
761 | 752 |
upper=0, |
... | ... |
@@ -783,7 +774,7 @@ class TestVault: |
783 | 774 |
""" |
784 | 775 |
Estimating the entropy and hash length for the degenerate case works. |
785 | 776 |
""" |
786 |
- v = Vault(phrase=self.phrase) |
|
777 |
+ v = vault.Vault(phrase=self.phrase) |
|
787 | 778 |
monkeypatch.setattr( |
788 | 779 |
v, |
789 | 780 |
'_estimate_sufficient_hash_length', |
... | ... |
@@ -805,7 +796,7 @@ class TestVault: |
805 | 796 |
) |
806 | 797 |
def test_224_binary_strings(self, s: str | bytes | bytearray) -> None: |
807 | 798 |
"""Byte string conversion is idempotent.""" |
808 |
- binstr = Vault._get_binary_string |
|
799 |
+ binstr = vault.Vault._get_binary_string |
|
809 | 800 |
if isinstance(s, str): |
810 | 801 |
assert binstr(s) == s.encode('UTF-8') |
811 | 802 |
assert binstr(binstr(s)) == s.encode('UTF-8') |
... | ... |
@@ -818,12 +809,12 @@ class TestVault: |
818 | 809 |
with pytest.raises( |
819 | 810 |
ValueError, match='requested passphrase length too short' |
820 | 811 |
): |
821 |
- Vault(phrase=self.phrase, symbol=100) |
|
812 |
+ vault.Vault(phrase=self.phrase, symbol=100) |
|
822 | 813 |
|
823 | 814 |
def test_311_no_viable_characters(self) -> None: |
824 | 815 |
"""Deriving passphrases without allowed characters fails.""" |
825 | 816 |
with pytest.raises(ValueError, match='no allowed characters left'): |
826 |
- Vault( |
|
817 |
+ vault.Vault( |
|
827 | 818 |
phrase=self.phrase, |
828 | 819 |
lower=0, |
829 | 820 |
upper=0, |
... | ... |
@@ -836,13 +827,13 @@ class TestVault: |
836 | 827 |
def test_320_character_set_subtraction_duplicate(self) -> None: |
837 | 828 |
"""Character sets do not contain duplicate characters.""" |
838 | 829 |
with pytest.raises(ValueError, match='duplicate characters'): |
839 |
- Vault._subtract(b'abcdef', b'aabbccddeeff') |
|
830 |
+ vault.Vault._subtract(b'abcdef', b'aabbccddeeff') |
|
840 | 831 |
with pytest.raises(ValueError, match='duplicate characters'): |
841 |
- Vault._subtract(b'aabbccddeeff', b'abcdef') |
|
832 |
+ vault.Vault._subtract(b'aabbccddeeff', b'abcdef') |
|
842 | 833 |
|
843 | 834 |
def test_322_hash_length_estimation(self) -> None: |
844 | 835 |
"""Hash length estimation rejects invalid safety factors.""" |
845 |
- v = Vault(phrase=self.phrase) |
|
836 |
+ v = vault.Vault(phrase=self.phrase) |
|
846 | 837 |
with pytest.raises(ValueError, match='invalid safety factor'): |
847 | 838 |
assert v._estimate_sufficient_hash_length(-1.0) |
848 | 839 |
with pytest.raises( |
849 | 840 |