-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_temptree.py
155 lines (117 loc) · 3.49 KB
/
test_temptree.py
1
2
3
4
5
6
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
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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
from os import altsep, curdir, pardir, sep
from hypothesis import HealthCheck, given, settings
from hypothesis.strategies import (
characters,
composite,
deferred,
dictionaries,
integers,
lists,
none,
one_of,
text,
)
from temptree import TemporaryTree
@composite
def filenames(draw):
"""Draws filenames.
Filenames are draw as text not containing some forbiden characters.
"""
forbiden_characters = []
for string in (sep, altsep, curdir, pardir, "\0"):
if string:
if len(string) == 1 and string not in forbiden_characters:
forbiden_characters.append(string)
else:
forbiden_characters.extend(
character
for character in string
if character not in forbiden_characters
)
return draw(
text(
alphabet=characters(
blacklist_categories=("Cs",), blacklist_characters=forbiden_characters
),
min_size=1,
max_size=10,
)
)
@composite
def filenames_lists(draw):
"""Draws lists of filenames."""
return draw(lists(filenames(), max_size=5))
@composite
def file_modes(draw):
"""Draws file modes.
File modes are draw as integers between 0o000 and 0o777.
"""
return draw(integers(min_value=0o000, max_value=0o777))
@composite
def file_contents(draw):
"""Draws file text content."""
return draw(
text(
alphabet=characters(
blacklist_categories=("Cs",), blacklist_characters=["\r"]
),
max_size=20,
)
)
@composite
def file_specs(draw):
"""Draws file specifications.
Files specifications are draw as a tuple of a file mode and file content, in any
order and maybe null.
"""
strategies = [none(), file_modes(), file_contents()]
first = draw(one_of(*strategies))
if first is None:
pass
elif isinstance(first, int):
strategies.pop(1)
elif isinstance(first, str):
strategies.pop(2)
else:
raise Exception(f"Value `{first}` does not match a known strategy")
second = draw(one_of(*strategies))
return (first, second)
directory_specs = deferred(
lambda: dictionaries(
keys=filenames(),
values=none()
| file_modes()
| file_contents()
| file_specs()
| filenames_lists()
| directory_specs,
max_size=5,
)
)
trees = filenames_lists() | directory_specs
@settings(suppress_health_check=[HealthCheck.too_slow])
@given(tree=trees)
def test_temporary_tree(tree):
def assert_on_tree(directory, tree):
if isinstance(tree, list):
tree = {name: None for name in tree}
for name, value in tree.items():
file = directory / name
if isinstance(value, (list, dict)):
assert file.is_dir()
assert_on_tree(file, value)
else:
assert file.is_file()
mode = None
content = None
if isinstance(value, int):
mode = value
elif isinstance(value, str):
content = value
if mode:
assert file.stat().st_mode == mode + 0o100000
if content:
assert file.read_text() == content
with TemporaryTree(tree) as root:
assert root.is_dir()
assert_on_tree(root, tree)