a101d1f604a3ad6de242989f7a4887b78ab012a1
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

1) # SPDX-FileCopyrightText: 2024 Marco Ricci <m@the13thletter.info>
2) #
3) # SPDX-License-Identifier: MIT
4) 
5) """Test passphrase generation via derivepassphrase.Vault."""
6) 
7) from __future__ import annotations
8) 
9) import math
10) from typing import Any
11) 
12) import pytest
13) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

14) import derivepassphrase
15) 
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

16) Vault = derivepassphrase.Vault
17) 
18) class TestVault:
19) 
20)     phrase = b'She cells C shells bye the sea shoars'
21)     google_phrase = rb': 4TVH#5:aZl8LueOT\{'
22)     twitter_phrase = rb"[ (HN_N:lI&<ro=)3'g9"
23) 
24)     @pytest.mark.parametrize(['service', 'expected'], [
25)         (b'google', google_phrase),
26)         ('twitter', twitter_phrase),
27)     ])
28)     def test_200_basic_configuration(self, service, expected):
29)         assert Vault(phrase=self.phrase).generate(service) == expected
30) 
31)     def test_201_phrase_dependence(self):
32)         assert (
33)             Vault(phrase=(self.phrase + b'X')).generate('google') ==
34)             b'n+oIz6sL>K*lTEWYRO%7'
35)         )
36) 
37)     def test_202_reproducibility_and_bytes_service_name(self):
38)         assert (
39)             Vault(phrase=self.phrase).generate(b'google') ==
40)             Vault(phrase=self.phrase).generate('google')
41)         )
42) 
43)     def test_203_reproducibility_and_bytearray_service_name(self):
44)         assert (
45)             Vault(phrase=self.phrase).generate(b'google') ==
46)             Vault(phrase=self.phrase).generate(bytearray(b'google'))
47)         )
48) 
49)     def test_210_nonstandard_length(self):
50)         assert (
51)             Vault(phrase=self.phrase, length=4).generate('google')
52)             == b'xDFu'
53)         )
54) 
55)     def test_211_repetition_limit(self):
56)         assert (
57)             Vault(phrase=b'', length=24, symbol=0, number=0,
58)                   repeat=1).generate('asd') ==
59)             b'IVTDzACftqopUXqDHPkuCIhV'
60)         )
61) 
62)     def test_212_without_symbols(self):
63)         assert (
64)             Vault(phrase=self.phrase, symbol=0).generate('google') ==
65)             b'XZ4wRe0bZCazbljCaMqR'
66)         )
67) 
68)     def test_213_no_numbers(self):
69)         assert (
70)             Vault(phrase=self.phrase, number=0).generate('google') ==
71)             b'_*$TVH.%^aZl(LUeOT?>'
72)         )
73) 
74)     def test_214_no_lowercase_letters(self):
75)         assert (
76)             Vault(phrase=self.phrase, lower=0).generate('google') ==
77)             b':{?)+7~@OA:L]!0E$)(+'
78)         )
79) 
80)     def test_215_at_least_5_digits(self):
81)         assert (
82)             Vault(phrase=self.phrase, length=8, number=5)
83)             .generate('songkick') == b'i0908.7['
84)         )
85) 
86)     def test_216_lots_of_spaces(self):
87)         assert (
88)             Vault(phrase=self.phrase, space=12)
89)             .generate('songkick') == b' c   6 Bq  % 5fR    '
90)         )
91) 
92)     def test_217_all_character_classes(self):
93)         assert (
94)             Vault(phrase=self.phrase, lower=2, upper=2, number=1,
95)                   space=3, dash=2, symbol=1)
96)             .generate('google') == b': : fv_wqt>a-4w1S  R'
97)         )
98) 
99)     def test_218_only_numbers_and_very_high_repetition_limit(self):
100)         generated = Vault(phrase=b'', length=40, lower=0, upper=0, space=0,
101)                           dash=0, symbol=0, repeat=4).generate('abcdef')
102)         forbidden_substrings = {b'0000', b'1111', b'2222', b'3333', b'4444',
103)                                 b'5555', b'6666', b'7777', b'8888', b'9999'}
104)         for substring in forbidden_substrings:
105)             assert substring not in generated
106) 
107)     def test_219_very_limited_character_set(self):
108)         generated = Vault(phrase=b'', length=24, lower=0, upper=0,
109)                           space=0, symbol=0).generate('testing')
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

110)         assert generated == b'763252593304946694588866'
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

111) 
112)     def test_220_character_set_subtraction(self):
113)         assert Vault._subtract(b'be', b'abcdef') == bytearray(b'acdf')
114) 
115)     @pytest.mark.parametrize(['length', 'settings', 'entropy'], [
116)         (20, {}, math.log2(math.factorial(20)) + 20 * math.log2(94)),
117)         (
118)             20,
119)             {'upper': 0, 'number': 0, 'space': 0, 'symbol': 0},
120)             math.log2(math.factorial(20)) + 20 * math.log2(26)
121)         ),
122)         (0, {}, float('-inf')),
123)         (0, {'lower': 0, 'number': 0, 'space': 0, 'symbol': 0}, float('-inf')),
124)         (1, {}, math.log2(94)),
125)         (1, {'upper': 0, 'lower': 0, 'number': 0, 'symbol': 0}, 0.0),
126)     ])
127)     def test_221_entropy(
128)         self, length: int, settings: dict[str, int], entropy: int
129)     ) -> None:
130)         v = Vault(length=length, **settings)  # type: ignore[arg-type]
131)         assert math.isclose(v._entropy(), entropy)
132)         assert v._estimate_sufficient_hash_length() > 0
133)         if math.isfinite(entropy) and entropy:
134)             assert (
135)                 v._estimate_sufficient_hash_length(1.0) ==
136)                 math.ceil(entropy / 8)
137)             )
138)         assert v._estimate_sufficient_hash_length(8.0) >= entropy
139) 
140)     def test_222_hash_length_estimation(self) -> None:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

141)         v = Vault(phrase=self.phrase, lower=0, upper=0, number=0,
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

142)                    symbol=0, space=1, length=1)
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 2 months ago

143)         assert v._entropy() == 0.0
144)         assert v._estimate_sufficient_hash_length() > 0
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

145) 
146)     @pytest.mark.parametrize(['service', 'expected'], [
147)         (b'google', google_phrase),
148)         ('twitter', twitter_phrase),
149)     ])
150)     def test_223_hash_length_expansion(
151)         self, monkeypatch: Any, service: str | bytes, expected: bytes
152)     ) -> None:
153)         v = Vault(phrase=self.phrase)
154)         monkeypatch.setattr(v,
155)                             '_estimate_sufficient_hash_length',
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

156)                             lambda *args, **kwargs: 1)  # noqa: ARG005
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

157)         assert v._estimate_sufficient_hash_length() < len(self.phrase)
158)         assert v.generate(service) == expected
159) 
160)     @pytest.mark.parametrize(['s', 'raises'], [
161)         ('ñ', True), ('Düsseldorf', True),
162)         ('liberté, egalité, fraternité', True), ('ASCII', False),
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

163)         (b'D\xc3\xbcsseldorf', False),
Marco Ricci Rename and regroup all test...

Marco Ricci authored 2 months ago

164)         (bytearray([2, 3, 5, 7, 11, 13]), False),
165)     ])
166)     def test_224_binary_strings(
167)         self, s: str | bytes | bytearray, raises: bool
168)     ) -> None:
169)         binstr = derivepassphrase.Vault._get_binary_string
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 1 month ago

170)         AmbiguousByteRepresentationError = (  # noqa: N806