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

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