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

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