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

Correctly handle fmt: skip comments without internal spaces (#2970)
[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 PREVIEW_CASES: List[str] = [
76     # string processing
77     "cantfit",
78     "comments7",
79     "comments8",
80     "long_strings",
81     "long_strings__edge_case",
82     "long_strings__regression",
83     "percent_precedence",
84     "remove_except_parens",
85     "remove_for_brackets",
86     "one_element_subscript",
87     "remove_await_parens",
88     "return_annotation_brackets",
89 ]
90
91 SOURCES: List[str] = [
92     "src/black/__init__.py",
93     "src/black/__main__.py",
94     "src/black/brackets.py",
95     "src/black/cache.py",
96     "src/black/comments.py",
97     "src/black/concurrency.py",
98     "src/black/const.py",
99     "src/black/debug.py",
100     "src/black/files.py",
101     "src/black/linegen.py",
102     "src/black/lines.py",
103     "src/black/mode.py",
104     "src/black/nodes.py",
105     "src/black/numerics.py",
106     "src/black/output.py",
107     "src/black/parsing.py",
108     "src/black/report.py",
109     "src/black/rusty.py",
110     "src/black/strings.py",
111     "src/black/trans.py",
112     "src/blackd/__init__.py",
113     "src/blib2to3/pygram.py",
114     "src/blib2to3/pytree.py",
115     "src/blib2to3/pgen2/conv.py",
116     "src/blib2to3/pgen2/driver.py",
117     "src/blib2to3/pgen2/grammar.py",
118     "src/blib2to3/pgen2/literals.py",
119     "src/blib2to3/pgen2/parse.py",
120     "src/blib2to3/pgen2/pgen.py",
121     "src/blib2to3/pgen2/tokenize.py",
122     "src/blib2to3/pgen2/token.py",
123     "setup.py",
124     "tests/test_black.py",
125     "tests/test_blackd.py",
126     "tests/test_format.py",
127     "tests/optional.py",
128     "tests/util.py",
129     "tests/conftest.py",
130 ]
131
132
133 @pytest.fixture(autouse=True)
134 def patch_dump_to_file(request: Any) -> Iterator[None]:
135     with patch("black.dump_to_file", dump_to_stderr):
136         yield
137
138
139 def check_file(filename: str, mode: black.Mode, *, data: bool = True) -> None:
140     source, expected = read_data(filename, data=data)
141     assert_format(source, expected, mode, fast=False)
142
143
144 @pytest.mark.parametrize("filename", SIMPLE_CASES)
145 def test_simple_format(filename: str) -> None:
146     check_file(filename, DEFAULT_MODE)
147
148
149 @pytest.mark.parametrize("filename", PREVIEW_CASES)
150 def test_preview_format(filename: str) -> None:
151     check_file(filename, black.Mode(preview=True))
152
153
154 @pytest.mark.parametrize("filename", SOURCES)
155 def test_source_is_formatted(filename: str) -> None:
156     path = THIS_DIR.parent / filename
157     check_file(str(path), DEFAULT_MODE, data=False)
158
159
160 # =============== #
161 # Complex cases
162 # ============= #
163
164
165 def test_empty() -> None:
166     source = expected = ""
167     assert_format(source, expected)
168
169
170 def test_pep_572() -> None:
171     source, expected = read_data("pep_572")
172     assert_format(source, expected, minimum_version=(3, 8))
173
174
175 def test_pep_572_remove_parens() -> None:
176     source, expected = read_data("pep_572_remove_parens")
177     assert_format(source, expected, minimum_version=(3, 8))
178
179
180 def test_pep_572_do_not_remove_parens() -> None:
181     source, expected = read_data("pep_572_do_not_remove_parens")
182     # the AST safety checks will fail, but that's expected, just make sure no
183     # parentheses are touched
184     assert_format(source, expected, fast=True)
185
186
187 @pytest.mark.parametrize("major, minor", [(3, 9), (3, 10)])
188 def test_pep_572_newer_syntax(major: int, minor: int) -> None:
189     source, expected = read_data(f"pep_572_py{major}{minor}")
190     assert_format(source, expected, minimum_version=(major, minor))
191
192
193 def test_pep_570() -> None:
194     source, expected = read_data("pep_570")
195     assert_format(source, expected, minimum_version=(3, 8))
196
197
198 def test_remove_with_brackets() -> None:
199     source, expected = read_data("remove_with_brackets")
200     assert_format(
201         source,
202         expected,
203         black.Mode(preview=True),
204         minimum_version=(3, 9),
205     )
206
207
208 @pytest.mark.parametrize("filename", PY310_CASES)
209 def test_python_310(filename: str) -> None:
210     source, expected = read_data(filename)
211     mode = black.Mode(target_versions={black.TargetVersion.PY310})
212     assert_format(source, expected, mode, minimum_version=(3, 10))
213
214
215 def test_python_310_without_target_version() -> None:
216     source, expected = read_data("pattern_matching_simple")
217     mode = black.Mode()
218     assert_format(source, expected, mode, minimum_version=(3, 10))
219
220
221 def test_patma_invalid() -> None:
222     source, expected = read_data("pattern_matching_invalid")
223     mode = black.Mode(target_versions={black.TargetVersion.PY310})
224     with pytest.raises(black.parsing.InvalidInput) as exc_info:
225         assert_format(source, expected, mode, minimum_version=(3, 10))
226
227     exc_info.match("Cannot parse: 10:11")
228
229
230 def test_python_2_hint() -> None:
231     with pytest.raises(black.parsing.InvalidInput) as exc_info:
232         assert_format("print 'daylily'", "print 'daylily'")
233     exc_info.match(black.parsing.PY2_HINT)
234
235
236 def test_docstring_no_string_normalization() -> None:
237     """Like test_docstring but with string normalization off."""
238     source, expected = read_data("docstring_no_string_normalization")
239     mode = replace(DEFAULT_MODE, string_normalization=False)
240     assert_format(source, expected, mode)
241
242
243 def test_long_strings_flag_disabled() -> None:
244     """Tests for turning off the string processing logic."""
245     source, expected = read_data("long_strings_flag_disabled")
246     mode = replace(DEFAULT_MODE, experimental_string_processing=False)
247     assert_format(source, expected, mode)
248
249
250 def test_numeric_literals() -> None:
251     source, expected = read_data("numeric_literals")
252     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
253     assert_format(source, expected, mode)
254
255
256 def test_numeric_literals_ignoring_underscores() -> None:
257     source, expected = read_data("numeric_literals_skip_underscores")
258     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
259     assert_format(source, expected, mode)
260
261
262 def test_stub() -> None:
263     mode = replace(DEFAULT_MODE, is_pyi=True)
264     source, expected = read_data("stub.pyi")
265     assert_format(source, expected, mode)
266
267
268 def test_python38() -> None:
269     source, expected = read_data("python38")
270     assert_format(source, expected, minimum_version=(3, 8))
271
272
273 def test_python39() -> None:
274     source, expected = read_data("python39")
275     assert_format(source, expected, minimum_version=(3, 9))
276
277
278 def test_power_op_newline() -> None:
279     # requires line_length=0
280     source, expected = read_data("power_op_newline")
281     assert_format(source, expected, mode=black.Mode(line_length=0))