Newer
Older
from diceware.random_sources import (
SystemRandomSource, RealDiceRandomSource,
)
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class TestSystemRandomSource(object):
def test_options_are_stored(self):
# options passed-in are stored with SystemRandomStource instances
options = "fake_options"
src = SystemRandomSource(options)
assert src.options is options
def test_has_choice_method(self):
# SystemRandomInstances provide a choice method
src = SystemRandomSource(None)
assert hasattr(src, 'choice')
def test_registered_as_system(self):
# The SystemRandomInstance is registered as entry point with
# name 'system' in group 'diceware_random_sources'
sources_dict = dict()
for entry_point in pkg_resources.iter_entry_points(
group="diceware_random_sources"):
sources_dict.update({entry_point.name: entry_point.load()})
assert 'system' in sources_dict
assert sources_dict['system'] == SystemRandomSource
def test_choice_accepts_lists_of_numbers(self):
# the choice() method accepts lists of numbers
src = SystemRandomSource(None)
assert src.choice([1, 2, 3]) in [1, 2, 3]
def test_choice_accepts_tuples_of_numbers(self):
# the choce() method accepts tuples of numbers
src = SystemRandomSource(None)
assert src.choice((1, 2, 3), ) in [1, 2, 3]
def test_choice_accepts_list_of_chars(self):
# the choice() method accepts lists of chars
src = SystemRandomSource(None)
assert src.choice(['a', 'b', 'c']) in ['a', 'b', 'c']
def test_choice_accepts_list_of_strings(self):
# the choice() method accepts lists of strings
src = SystemRandomSource(None)
assert src.choice(['foo', 'bar', 'baz']) in ['foo', 'bar', 'baz']
def test_choice_picks_all_items(self):
# make sure all items of a sequence are picked (in the long run)
sequence = [1, 2, 3, 4]
picked = set()
num = 10 ** 3
src = SystemRandomSource(None)
while num:
picked.add(src.choice(sequence))
if len(picked) == len(sequence):
break
num -= 1
assert num > 0
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class InputMock(object):
"""A replacement for input() or raw_input() respectively.
This mock, when called, mimics input() behaviour, outputs a prompt,
etc., but does not wait for real key strokes. Instead it returns the
next value from `fake_input_values` given on initialization:
>>> faked_input = InputMock(["val1", "val2", "1"])
>>> faked_input("Give a value: ")
Give a value: val1
'val1'
>>> faked_input("And another value: ")
And another value: val2
'val2'
>>> faked_input()
1
'1'
To be used with the `monkeypatch` pytest fixture, to replace
`diceware.random_sources.input_func`.
"""
fake_input_values = []
def __init__(self, fake_input_values=[]):
self.fake_input_values = fake_input_values
self.fake_input_values.reverse()
def __call__(self, prompt=''):
curr_value = self.fake_input_values.pop()
print("%s%s" % (prompt, curr_value))
return curr_value
class TestRealDiceRandomSource(object):
@classmethod
def fake_input_values(cls, values, patch):
input_mock = InputMock(values)
patch.setattr(
# function to replace, replacement
"diceware.random_sources.input_func", input_mock)
return input_mock
def test_raw_input_patch_works(self, monkeypatch, capsys):
# make sure our fake input works. We try to fake input ('foo',
# 'bar') and make sure that output is captured.
# This test is just a hint, how input could be faked in real tests.
# It can (and should) be removed if not needed any more.
self.fake_input_values(["foo", "bar"], monkeypatch)
# late import, because we need the patched version
from diceware.random_sources import input_func
result1 = input_func("Enter some values: ")
result2 = input_func("Enter more values: ")
assert result2 == "bar"
out, err = capsys.readouterr() # captured stdout/stderr
assert out == "Enter some values: foo\nEnter more values: bar\n"
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def test_options_are_stored(self):
# options passed-in are stored with RealDiceRandomSource instances
options = "fake_options"
src = RealDiceRandomSource(options)
assert src.options is options
def test_has_choice_method(self):
# RealDiceRandomSource instances provide a choice method
src = RealDiceRandomSource(None)
assert hasattr(src, 'choice')
def test_registered_as_realdice(self):
# The RealDiceRandomSource is registered as entry point with
# name 'realdice' in group 'diceware_random_sources'
sources_dict = dict()
for entry_point in pkg_resources.iter_entry_points(
group="diceware_random_sources"):
sources_dict.update({entry_point.name: entry_point.load()})
assert 'realdice' in sources_dict
assert sources_dict['realdice'] == RealDiceRandomSource
def test_choice_accepts_lists_of_numbers(self, monkeypatch):
# the choice() method accepts lists of numbers
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
assert src.choice([11, 12, 13, 14, 15, 16]) == 11
def test_choice_accepts_tuples_of_numbers(self, monkeypatch):
# the choice() method accepts tuples of numbers
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
assert src.choice((11, 12, 13, 14, 15, 16), ) == 11
def test_choice_accepts_list_of_chars(self, monkeypatch):
# the choice() method accepts lists of chars
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
assert src.choice(['a', 'b', 'c', 'd', 'e', 'f']) == 'a'
def test_choice_accepts_list_of_strings(self, monkeypatch):
# the choice() method accepts lists of strings
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
assert src.choice(
['val1', 'val2', 'val3', 'val4', 'val5', 'val6']) == "val1"
def test_choice_num_of_dice_for_seq_len36(self, monkeypatch):
# choice() requires two dice for a sequence len of 6**2
self.fake_input_values(["1", "2"], monkeypatch)
src = RealDiceRandomSource(None)
sequence = list(range(6 ** 2))
expected_index = 6 * (1 - 1) + (2 - 1) # = 6 x roll_1 + roll_2 - 1
assert src.choice(sequence) == sequence[expected_index]
def test_choice_num_of_dice_for_seq_len216(self, monkeypatch):
# choice() requires three dice for a sequence len of 6**3
self.fake_input_values(["1", "2", "3"], monkeypatch)
src = RealDiceRandomSource(None)
sequence = list(range(6 ** 3)) # 216
expected_index = 0 + 6 + 3 - 1 # = 6^2 x (roll_1 - 1)
# + 6^1 x (roll_2 - 1)
# + roll_3 - 1
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
assert src.choice(sequence) == sequence[expected_index]
def test_hint_if_entropy_is_decreased(self, monkeypatch, capsys):
# if len of choice is not a multiple of 6, entropy is decreased
# (not the whole sequence is taken into consideration). We get
# a warning in that case.
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
picked = src.choice([1, 2, 3, 4, 5, 6, 7])
assert picked == 1
out, err = capsys.readouterr()
assert "entropy is reduced" in out
assert err == ""
def test_non_numbers_as_input_are_rejected(self, monkeypatch):
# Users might input non-numbers. We ask again then.
self.fake_input_values(["no-number", "", "1"], monkeypatch)
src = RealDiceRandomSource(None)
assert src.choice([1, 2, 3, 4, 5, 6]) == 1
def test_choice_len_too_short(self, monkeypatch):
# We raise an exception if choice gets less than 6 elements.
self.fake_input_values(["1"], monkeypatch)
src = RealDiceRandomSource(None)
with pytest.raises(ValueError):
assert src.choice([1, 2, 3, 4, 5]) # list len < 6