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

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