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

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