]> git.madduck.net Git - etc/vim.git/blob - tests/test_format.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Hint at likely cause of ast parsing failure in error message (#2786)
[etc/vim.git] / tests / test_format.py
1 from dataclasses import replace
2 from typing import Any, Iterator, List
3 from unittest.mock import patch
4
5 import pytest
6
7 import black
8 from tests.util import (
9     DEFAULT_MODE,
10     PY36_VERSIONS,
11     THIS_DIR,
12     assert_format,
13     dump_to_stderr,
14     read_data,
15 )
16
17 SIMPLE_CASES: List[str] = [
18     "beginning_backslash",
19     "bracketmatch",
20     "class_blank_parentheses",
21     "class_methods_new_line",
22     "collections",
23     "comments",
24     "comments2",
25     "comments3",
26     "comments4",
27     "comments5",
28     "comments6",
29     "comments_non_breaking_space",
30     "comment_after_escaped_newline",
31     "composition",
32     "composition_no_trailing_comma",
33     "docstring",
34     "empty_lines",
35     "expression",
36     "fmtonoff",
37     "fmtonoff2",
38     "fmtonoff3",
39     "fmtonoff4",
40     "fmtskip",
41     "fmtskip2",
42     "fmtskip3",
43     "fmtskip4",
44     "fmtskip5",
45     "fmtskip6",
46     "fstring",
47     "function",
48     "function2",
49     "function_trailing_comma",
50     "import_spacing",
51     "remove_parens",
52     "slices",
53     "string_prefixes",
54     "tricky_unicode_symbols",
55     "tupleassign",
56 ]
57
58 PY310_CASES: List[str] = [
59     "pattern_matching_simple",
60     "pattern_matching_complex",
61     "pattern_matching_extras",
62     "pattern_matching_style",
63     "pattern_matching_generic",
64     "parenthesized_context_managers",
65 ]
66
67 PREVIEW_CASES: List[str] = [
68     # string processing
69     "cantfit",
70     "comments7",
71     "long_strings",
72     "long_strings__edge_case",
73     "long_strings__regression",
74     "percent_precedence",
75 ]
76
77 SOURCES: List[str] = [
78     "src/black/__init__.py",
79     "src/black/__main__.py",
80     "src/black/brackets.py",
81     "src/black/cache.py",
82     "src/black/comments.py",
83     "src/black/concurrency.py",
84     "src/black/const.py",
85     "src/black/debug.py",
86     "src/black/files.py",
87     "src/black/linegen.py",
88     "src/black/lines.py",
89     "src/black/mode.py",
90     "src/black/nodes.py",
91     "src/black/numerics.py",
92     "src/black/output.py",
93     "src/black/parsing.py",
94     "src/black/report.py",
95     "src/black/rusty.py",
96     "src/black/strings.py",
97     "src/black/trans.py",
98     "src/blackd/__init__.py",
99     "src/black_primer/cli.py",
100     "src/black_primer/lib.py",
101     "src/blib2to3/pygram.py",
102     "src/blib2to3/pytree.py",
103     "src/blib2to3/pgen2/conv.py",
104     "src/blib2to3/pgen2/driver.py",
105     "src/blib2to3/pgen2/grammar.py",
106     "src/blib2to3/pgen2/literals.py",
107     "src/blib2to3/pgen2/parse.py",
108     "src/blib2to3/pgen2/pgen.py",
109     "src/blib2to3/pgen2/tokenize.py",
110     "src/blib2to3/pgen2/token.py",
111     "setup.py",
112     "tests/test_black.py",
113     "tests/test_blackd.py",
114     "tests/test_format.py",
115     "tests/test_primer.py",
116     "tests/optional.py",
117     "tests/util.py",
118     "tests/conftest.py",
119 ]
120
121
122 @pytest.fixture(autouse=True)
123 def patch_dump_to_file(request: Any) -> Iterator[None]:
124     with patch("black.dump_to_file", dump_to_stderr):
125         yield
126
127
128 def check_file(filename: str, mode: black.Mode, *, data: bool = True) -> None:
129     source, expected = read_data(filename, data=data)
130     assert_format(source, expected, mode, fast=False)
131
132
133 @pytest.mark.parametrize("filename", SIMPLE_CASES)
134 def test_simple_format(filename: str) -> None:
135     check_file(filename, DEFAULT_MODE)
136
137
138 @pytest.mark.parametrize("filename", PREVIEW_CASES)
139 def test_preview_format(filename: str) -> None:
140     check_file(filename, black.Mode(preview=True))
141
142
143 @pytest.mark.parametrize("filename", SOURCES)
144 def test_source_is_formatted(filename: str) -> None:
145     path = THIS_DIR.parent / filename
146     check_file(str(path), DEFAULT_MODE, data=False)
147
148
149 # =============== #
150 # Complex cases
151 # ============= #
152
153
154 def test_empty() -> None:
155     source = expected = ""
156     assert_format(source, expected)
157
158
159 def test_pep_572() -> None:
160     source, expected = read_data("pep_572")
161     assert_format(source, expected, minimum_version=(3, 8))
162
163
164 def test_pep_572_remove_parens() -> None:
165     source, expected = read_data("pep_572_remove_parens")
166     assert_format(source, expected, minimum_version=(3, 8))
167
168
169 def test_pep_572_do_not_remove_parens() -> None:
170     source, expected = read_data("pep_572_do_not_remove_parens")
171     # the AST safety checks will fail, but that's expected, just make sure no
172     # parentheses are touched
173     assert_format(source, expected, fast=True)
174
175
176 @pytest.mark.parametrize("major, minor", [(3, 9), (3, 10)])
177 def test_pep_572_newer_syntax(major: int, minor: int) -> None:
178     source, expected = read_data(f"pep_572_py{major}{minor}")
179     assert_format(source, expected, minimum_version=(major, minor))
180
181
182 def test_pep_570() -> None:
183     source, expected = read_data("pep_570")
184     assert_format(source, expected, minimum_version=(3, 8))
185
186
187 @pytest.mark.parametrize("filename", PY310_CASES)
188 def test_python_310(filename: str) -> None:
189     source, expected = read_data(filename)
190     mode = black.Mode(target_versions={black.TargetVersion.PY310})
191     assert_format(source, expected, mode, minimum_version=(3, 10))
192
193
194 def test_patma_invalid() -> None:
195     source, expected = read_data("pattern_matching_invalid")
196     mode = black.Mode(target_versions={black.TargetVersion.PY310})
197     with pytest.raises(black.parsing.InvalidInput) as exc_info:
198         assert_format(source, expected, mode, minimum_version=(3, 10))
199
200     exc_info.match("Cannot parse: 10:11")
201
202
203 def test_patma_hint() -> None:
204     source, expected = read_data("pattern_matching_simple")
205     mode = black.Mode(target_versions={black.TargetVersion.PY39})
206     with pytest.raises(black.parsing.InvalidInput) as exc_info:
207         assert_format(source, expected, mode, minimum_version=(3, 10))
208
209     exc_info.match(black.parsing.PY310_HINT)
210
211
212 def test_python_2_hint() -> None:
213     with pytest.raises(black.parsing.InvalidInput) as exc_info:
214         assert_format("print 'daylily'", "print 'daylily'")
215     exc_info.match(black.parsing.PY2_HINT)
216
217
218 def test_docstring_no_string_normalization() -> None:
219     """Like test_docstring but with string normalization off."""
220     source, expected = read_data("docstring_no_string_normalization")
221     mode = replace(DEFAULT_MODE, string_normalization=False)
222     assert_format(source, expected, mode)
223
224
225 def test_long_strings_flag_disabled() -> None:
226     """Tests for turning off the string processing logic."""
227     source, expected = read_data("long_strings_flag_disabled")
228     mode = replace(DEFAULT_MODE, experimental_string_processing=False)
229     assert_format(source, expected, mode)
230
231
232 def test_numeric_literals() -> None:
233     source, expected = read_data("numeric_literals")
234     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
235     assert_format(source, expected, mode)
236
237
238 def test_numeric_literals_ignoring_underscores() -> None:
239     source, expected = read_data("numeric_literals_skip_underscores")
240     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
241     assert_format(source, expected, mode)
242
243
244 def test_stub() -> None:
245     mode = replace(DEFAULT_MODE, is_pyi=True)
246     source, expected = read_data("stub.pyi")
247     assert_format(source, expected, mode)
248
249
250 def test_python38() -> None:
251     source, expected = read_data("python38")
252     assert_format(source, expected, minimum_version=(3, 8))
253
254
255 def test_python39() -> None:
256     source, expected = read_data("python39")
257     assert_format(source, expected, minimum_version=(3, 9))