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

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