1"""Tests for the flake8.style_guide.DecisionEngine class."""
2import argparse
3
4import pytest
5
6from flake8 import defaults
7from flake8 import style_guide
8
9
10def create_options(**kwargs):
11    """Create and return an instance of argparse.Namespace."""
12    kwargs.setdefault("select", [])
13    kwargs.setdefault("extended_default_ignore", [])
14    kwargs.setdefault("extended_default_select", [])
15    kwargs.setdefault("extend_select", [])
16    kwargs.setdefault("ignore", [])
17    kwargs.setdefault("extend_ignore", [])
18    kwargs.setdefault("disable_noqa", False)
19    kwargs.setdefault("enable_extensions", [])
20    return argparse.Namespace(**kwargs)
21
22
23@pytest.mark.parametrize(
24    "ignore_list,extend_ignore,error_code",
25    [
26        (["E111", "E121"], [], "E111"),
27        (["E111", "E121"], [], "E121"),
28        (["E111"], ["E121"], "E121"),
29        (["E11", "E12"], [], "E121"),
30        (["E2", "E12"], [], "E121"),
31        (["E2", "E12"], [], "E211"),
32        (["E2", "E3"], ["E12"], "E211"),
33    ],
34)
35def test_was_ignored_ignores_errors(ignore_list, extend_ignore, error_code):
36    """Verify we detect users explicitly ignoring an error."""
37    decider = style_guide.DecisionEngine(
38        create_options(ignore=ignore_list, extend_ignore=extend_ignore)
39    )
40
41    assert decider.was_ignored(error_code) is style_guide.Ignored.Explicitly
42
43
44@pytest.mark.parametrize(
45    "ignore_list,extend_ignore,error_code",
46    [
47        (["E111", "E121"], [], "E112"),
48        (["E111", "E121"], [], "E122"),
49        (["E11", "E12"], ["E121"], "W121"),
50        (["E2", "E12"], [], "E112"),
51        (["E2", "E12"], [], "E111"),
52        (["E2", "E12"], ["W11", "E3"], "E111"),
53    ],
54)
55def test_was_ignored_implicitly_selects_errors(
56    ignore_list, extend_ignore, error_code
57):
58    """Verify we detect users does not explicitly ignore an error."""
59    decider = style_guide.DecisionEngine(
60        create_options(ignore=ignore_list, extend_ignore=extend_ignore)
61    )
62
63    assert decider.was_ignored(error_code) is style_guide.Selected.Implicitly
64
65
66@pytest.mark.parametrize(
67    "select_list,extend_select,enable_extensions,error_code",
68    [
69        (["E111", "E121"], [], [], "E111"),
70        (["E111", "E121"], [], [], "E121"),
71        (["E11", "E12"], [], [], "E121"),
72        (["E2", "E12"], [], [], "E121"),
73        (["E2", "E12"], [], [], "E211"),
74        (["E1"], ["E2"], [], "E211"),
75        (["E1"], [], ["E2"], "E211"),
76        ([], ["E2"], [], "E211"),
77        ([], [], ["E2"], "E211"),
78        (["E1"], ["E2"], [], "E211"),
79        (["E111"], ["E121"], ["E2"], "E121"),
80    ],
81)
82def test_was_selected_selects_errors(
83    select_list, extend_select, enable_extensions, error_code
84):
85    """Verify we detect users explicitly selecting an error."""
86    decider = style_guide.DecisionEngine(
87        options=create_options(
88            select=select_list,
89            extend_select=extend_select,
90            enable_extensions=enable_extensions,
91        ),
92    )
93
94    assert decider.was_selected(error_code) is style_guide.Selected.Explicitly
95
96
97def test_was_selected_implicitly_selects_errors():
98    """Verify we detect users implicitly selecting an error."""
99    error_code = "E121"
100    decider = style_guide.DecisionEngine(
101        create_options(
102            select=[],
103            extended_default_select=["E"],
104        ),
105    )
106
107    assert decider.was_selected(error_code) is style_guide.Selected.Implicitly
108
109
110@pytest.mark.parametrize(
111    "select_list,error_code",
112    [
113        (["E111", "E121"], "E112"),
114        (["E111", "E121"], "E122"),
115        (["E11", "E12"], "E132"),
116        (["E2", "E12"], "E321"),
117        (["E2", "E12"], "E410"),
118    ],
119)
120def test_was_selected_excludes_errors(select_list, error_code):
121    """Verify we detect users implicitly excludes an error."""
122    decider = style_guide.DecisionEngine(create_options(select=select_list))
123
124    assert decider.was_selected(error_code) is style_guide.Ignored.Implicitly
125
126
127@pytest.mark.parametrize(
128    "select_list,ignore_list,extend_ignore,error_code,expected",
129    [
130        (["E111", "E121"], [], [], "E111", style_guide.Decision.Selected),
131        (["E111", "E121"], [], [], "E112", style_guide.Decision.Ignored),
132        (["E111", "E121"], [], [], "E121", style_guide.Decision.Selected),
133        (["E111", "E121"], [], [], "E122", style_guide.Decision.Ignored),
134        (["E11", "E12"], [], [], "E132", style_guide.Decision.Ignored),
135        (["E2", "E12"], [], [], "E321", style_guide.Decision.Ignored),
136        (["E2", "E12"], [], [], "E410", style_guide.Decision.Ignored),
137        (["E11", "E121"], ["E1"], [], "E112", style_guide.Decision.Selected),
138        (["E11", "E121"], [], ["E1"], "E112", style_guide.Decision.Selected),
139        (
140            ["E111", "E121"],
141            ["E2"],
142            ["E3"],
143            "E122",
144            style_guide.Decision.Ignored,
145        ),
146        (["E11", "E12"], ["E13"], [], "E132", style_guide.Decision.Ignored),
147        (["E1", "E3"], ["E32"], [], "E321", style_guide.Decision.Ignored),
148        ([], ["E2", "E12"], [], "E410", style_guide.Decision.Ignored),
149        (
150            ["E4"],
151            ["E2", "E12", "E41"],
152            [],
153            "E410",
154            style_guide.Decision.Ignored,
155        ),
156        (
157            ["E41"],
158            ["E2", "E12", "E4"],
159            [],
160            "E410",
161            style_guide.Decision.Selected,
162        ),
163        (["E"], ["F"], [], "E410", style_guide.Decision.Selected),
164        (["F"], [], [], "E410", style_guide.Decision.Ignored),
165        (["E"], defaults.IGNORE, [], "E126", style_guide.Decision.Selected),
166        (["W"], defaults.IGNORE, [], "E126", style_guide.Decision.Ignored),
167        (["E"], defaults.IGNORE, [], "W391", style_guide.Decision.Ignored),
168        (["E", "W"], ["E13"], [], "E131", style_guide.Decision.Ignored),
169        (defaults.SELECT, ["E13"], [], "E131", style_guide.Decision.Ignored),
170        (
171            defaults.SELECT,
172            defaults.IGNORE,
173            ["W391"],
174            "E126",
175            style_guide.Decision.Ignored,
176        ),
177        (
178            defaults.SELECT,
179            defaults.IGNORE,
180            [],
181            "W391",
182            style_guide.Decision.Selected,
183        ),
184    ],
185)
186def test_decision_for(
187    select_list, ignore_list, extend_ignore, error_code, expected
188):
189    """Verify we decide when to report an error."""
190    decider = style_guide.DecisionEngine(
191        create_options(
192            select=select_list,
193            ignore=ignore_list,
194            extend_ignore=extend_ignore,
195        )
196    )
197
198    assert decider.decision_for(error_code) is expected
199
200
201@pytest.mark.parametrize(
202    "select,ignore,extended_default_ignore,extended_default_select,"
203    "enabled_extensions,error_code,expected",
204    [
205        (
206            defaults.SELECT,
207            [],
208            [],
209            ["I1"],
210            [],
211            "I100",
212            style_guide.Decision.Selected,
213        ),
214        (
215            defaults.SELECT,
216            [],
217            [],
218            ["I1"],
219            [],
220            "I201",
221            style_guide.Decision.Ignored,
222        ),
223        (
224            defaults.SELECT,
225            ["I2"],
226            [],
227            ["I1"],
228            [],
229            "I101",
230            style_guide.Decision.Selected,
231        ),
232        (
233            defaults.SELECT,
234            ["I2"],
235            [],
236            ["I1"],
237            [],
238            "I201",
239            style_guide.Decision.Ignored,
240        ),
241        (
242            defaults.SELECT,
243            ["I1"],
244            [],
245            ["I10"],
246            [],
247            "I101",
248            style_guide.Decision.Selected,
249        ),
250        (
251            defaults.SELECT,
252            ["I10"],
253            [],
254            ["I1"],
255            [],
256            "I101",
257            style_guide.Decision.Ignored,
258        ),
259        (
260            defaults.SELECT,
261            [],
262            [],
263            [],
264            ["U4"],
265            "U401",
266            style_guide.Decision.Selected,
267        ),
268        (
269            defaults.SELECT,
270            ["U401"],
271            [],
272            [],
273            ["U4"],
274            "U401",
275            style_guide.Decision.Ignored,
276        ),
277        (
278            defaults.SELECT,
279            ["U401"],
280            [],
281            [],
282            ["U4"],
283            "U402",
284            style_guide.Decision.Selected,
285        ),
286        (
287            ["E", "W"],
288            ["E13"],
289            [],
290            [],
291            [],
292            "E131",
293            style_guide.Decision.Ignored,
294        ),
295        (
296            ["E", "W"],
297            ["E13"],
298            [],
299            [],
300            [],
301            "E126",
302            style_guide.Decision.Selected,
303        ),
304        (["E2"], ["E21"], [], [], [], "E221", style_guide.Decision.Selected),
305        (["E2"], ["E21"], [], [], [], "E212", style_guide.Decision.Ignored),
306        (
307            ["F", "W"],
308            ["C90"],
309            [],
310            ["I1"],
311            [],
312            "C901",
313            style_guide.Decision.Ignored,
314        ),
315        (
316            ["E", "W"],
317            ["C"],
318            [],
319            [],
320            [],
321            "E131",
322            style_guide.Decision.Selected,
323        ),
324        (
325            defaults.SELECT,
326            defaults.IGNORE,
327            [],
328            [],
329            ["I"],
330            "I101",
331            style_guide.Decision.Selected,
332        ),
333        (
334            defaults.SELECT,
335            defaults.IGNORE,
336            [],
337            ["G"],
338            ["I"],
339            "G101",
340            style_guide.Decision.Selected,
341        ),
342        (
343            defaults.SELECT,
344            ["G1"],
345            [],
346            ["G"],
347            ["I"],
348            "G101",
349            style_guide.Decision.Ignored,
350        ),
351        (
352            defaults.SELECT,
353            ["E126"],
354            [],
355            [],
356            ["I"],
357            "I101",
358            style_guide.Decision.Selected,
359        ),
360        (
361            ["E", "W"],
362            defaults.IGNORE,
363            [],
364            ["I"],
365            [],
366            "I101",
367            style_guide.Decision.Ignored,
368        ),
369        (
370            ["E", "W", "I101"],
371            defaults.IGNORE + ("I101",),
372            ["I101"],
373            [],
374            [],
375            "I101",
376            style_guide.Decision.Selected,
377        ),
378        (
379            ["E", "W"],
380            defaults.IGNORE + ("I101",),
381            ["I101"],
382            [],
383            [],
384            "I101",
385            style_guide.Decision.Ignored,
386        ),
387        # TODO(sigmavirus24) Figure out how to exercise the final catch-all
388        # return statement
389    ],
390)
391def test_more_specific_decision_for_logic(
392    select,
393    ignore,
394    extended_default_ignore,
395    extended_default_select,
396    enabled_extensions,
397    error_code,
398    expected,
399):
400    """Verify the logic of DecisionEngine.more_specific_decision_for."""
401    decider = style_guide.DecisionEngine(
402        create_options(
403            select=select,
404            ignore=ignore,
405            extended_default_select=extended_default_select,
406            extended_default_ignore=extended_default_ignore,
407            enable_extensions=enabled_extensions,
408        ),
409    )
410
411    assert decider.more_specific_decision_for(error_code) is expected
412