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

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