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

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