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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
"""Tests for parsing the privileges checks specification."""
import pytest
from gn_libs.privileges import parse, SpecificationValueError
## NOTE: Should we limit depth of nesting of checks, e.g. don't do more than
## 3 levels or so?
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec",
("",
"(AND)",
"(AND (OR))",
"(OR (AND))",
"(OR (AND (OR (AND ))))"))
def test_empty_spec(spec):
"""
GIVEN: An effectively empty specification
WHEN: The specification is parsed
THEN: Raise a `SpecificationValueError`
"""
with pytest.raises(SpecificationValueError):
parse(spec)
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(AND priv1)", ("AND", ("priv1",))),
("(AND priv1 priv2)", ("AND", ("priv1", "priv2"))),
("(AND priv1 priv2 priv3)", ("AND", ("priv1", "priv2", "priv3"))),
("(and priv1)", ("AND", ("priv1",))),
("(and priv1 priv2)", ("AND", ("priv1", "priv2"))),
("(and priv1 priv2 priv3)", ("AND", ("priv1", "priv2", "priv3"))),
("(and priv1 priv2 (and priv3 priv4))",
("AND", ("priv1", "priv2", "priv3", "priv4")))))
def test_and(spec, expected):
"""
GIVEN: A simple 'AND' privileges check specification `spec`
WHEN: The specification is parsed
THEN: Verify the parsed output gives an 'AND' check object
"""
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(OR priv1)", ("OR", ("priv1",))),
("(OR priv1 priv2)", ("OR", ("priv1", "priv2"))),
("(OR priv1 priv2 priv3)", ("OR", ("priv1", "priv2", "priv3"))),
("(or priv1)", ("OR", ("priv1",))),
("(or priv1 priv2)", ("OR", ("priv1", "priv2"))),
("(or priv1 priv2 priv3)", ("OR", ("priv1", "priv2", "priv3")))))
def test_or(spec, expected):
"""
GIVEN: A simple 'OR' privileges check specification `spec`
WHEN: The specification is parsed
THEN: Verify the parsed output gives an 'OR' check object
"""
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(or priv1 priv2 (or priv3 priv4))",
("OR", ("priv1", "priv2", "priv3", "priv4"))),
("(and priv1 priv2 (and priv3 priv4))",
("AND", ("priv1", "priv2", "priv3", "priv4")))))
def test_merging(spec, expected):
"""
GIVEN:
- A nested specification where 2 or more of subsequent operators are
- the same
WHEN: The specification is parsed
THEN: Verify the parsed output merges the checks into a single object
"""
# NOTE: The "given-when-then" description above does not please me.
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(AND priv1 (or priv2 priv3))",
("AND", ("priv1",), ("OR", ("priv2", "priv3")))),))
def test_and_or(spec, expected):
"""
GIVEN:
- A specification beginning with an "AND" operator followed by an "OR"
- operator
WHEN: The specification is parsed
THEN: Verify the parsed output is correct
"""
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(OR priv1 priv2 priv3 (and priv4 priv5))",
("OR", ("priv1", "priv2", "priv3"), ("AND", ("priv4", "priv5")))),))
def test_or_and(spec, expected):
"""
GIVEN:
- A specification beginning with an "OR" operator followed by an "AND"
- operator
WHEN: The specification is parsed
THEN: Verify the parsed output is correct
"""
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec",
("()",
"this is invalid",
"priv1 AND priv2",
"(priv1 AND priv2)",
"(AND priv1 priv2 priv3"))
def test_invalid(spec):
"""
GIVEN: An invalid specification
WHEN: The specification is parsed
THEN: Verify that the `SpecificationValueError` is raised
"""
# NOTE: Maybe use hypothesis to generate random strings?
with pytest.raises(SpecificationValueError):
assert parse(spec)
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(("(AND priv1 (or priv2 priv3) priv4 (and priv5 priv6))",
("AND",
("priv1", "priv4", "priv5", "priv6"),
("OR", ("priv2", "priv3")))),))
def test_complex(spec, expected):
"""
GIVEN: An valid, but more complex specification
WHEN: The specification is parsed
THEN: Verify that the specification parses correctly
"""
assert parse(spec) == expected
@pytest.mark.unit_test
@pytest.mark.parametrize(
"spec,expected",
(
# -- We need to be careful about reduction --
# -- Please revisit your boolean logic to verify --
# -- how to reduce boolean statements. --
# ("(AND priv1 (or priv2 priv3) priv4 (or priv5 priv6))",
# ("AND",
# ("priv1", "priv4"),
# ("OR", ("priv2", "priv3", "priv5", "priv6")))),
("(OR priv1 (or priv2 priv3 (or priv4 priv5)) (or priv6 priv7))",
("OR", ("priv1", "priv6", "priv7", "priv2", "priv3", "priv4", "priv5"))),))
def test_reduction(spec, expected):
"""
GIVEN: A spec that can be reduced
WHEN: The specification is parsed
THEN:
- Verify that after parsing, it is reduced to the minimum number of levels
- possible.
"""
assert parse(spec) == expected
|