]> 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:

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