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

Enforce no formatting changes for PRs via CI (GH-2951)
[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 @pytest.mark.parametrize("filename", PY310_CASES)
196 def test_python_310(filename: str) -> None:
197     source, expected = read_data(filename)
198     mode = black.Mode(target_versions={black.TargetVersion.PY310})
199     assert_format(source, expected, mode, minimum_version=(3, 10))
200
201
202 def test_python_310_without_target_version() -> None:
203     source, expected = read_data("pattern_matching_simple")
204     mode = black.Mode()
205     assert_format(source, expected, mode, minimum_version=(3, 10))
206
207
208 def test_patma_invalid() -> None:
209     source, expected = read_data("pattern_matching_invalid")
210     mode = black.Mode(target_versions={black.TargetVersion.PY310})
211     with pytest.raises(black.parsing.InvalidInput) as exc_info:
212         assert_format(source, expected, mode, minimum_version=(3, 10))
213
214     exc_info.match("Cannot parse: 10:11")
215
216
217 def test_python_2_hint() -> None:
218     with pytest.raises(black.parsing.InvalidInput) as exc_info:
219         assert_format("print 'daylily'", "print 'daylily'")
220     exc_info.match(black.parsing.PY2_HINT)
221
222
223 def test_docstring_no_string_normalization() -> None:
224     """Like test_docstring but with string normalization off."""
225     source, expected = read_data("docstring_no_string_normalization")
226     mode = replace(DEFAULT_MODE, string_normalization=False)
227     assert_format(source, expected, mode)
228
229
230 def test_long_strings_flag_disabled() -> None:
231     """Tests for turning off the string processing logic."""
232     source, expected = read_data("long_strings_flag_disabled")
233     mode = replace(DEFAULT_MODE, experimental_string_processing=False)
234     assert_format(source, expected, mode)
235
236
237 def test_numeric_literals() -> None:
238     source, expected = read_data("numeric_literals")
239     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
240     assert_format(source, expected, mode)
241
242
243 def test_numeric_literals_ignoring_underscores() -> None:
244     source, expected = read_data("numeric_literals_skip_underscores")
245     mode = replace(DEFAULT_MODE, target_versions=PY36_VERSIONS)
246     assert_format(source, expected, mode)
247
248
249 def test_stub() -> None:
250     mode = replace(DEFAULT_MODE, is_pyi=True)
251     source, expected = read_data("stub.pyi")
252     assert_format(source, expected, mode)
253
254
255 def test_python38() -> None:
256     source, expected = read_data("python38")
257     assert_format(source, expected, minimum_version=(3, 8))
258
259
260 def test_python39() -> None:
261     source, expected = read_data("python39")
262     assert_format(source, expected, minimum_version=(3, 9))
263
264
265 def test_power_op_newline() -> None:
266     # requires line_length=0
267     source, expected = read_data("power_op_newline")
268     assert_format(source, expected, mode=black.Mode(line_length=0))