]> git.madduck.net Git - etc/vim.git/blob - tests/test_black.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:

30ecaf693a4346f0a487074d38969c29ece034d1
[etc/vim.git] / tests / test_black.py
1 #!/usr/bin/env python3
2 from functools import partial
3 from io import StringIO
4 import os
5 from pathlib import Path
6 import sys
7 from typing import Any, List, Tuple
8 import unittest
9 from unittest.mock import patch
10
11 from click import unstyle
12
13 import black
14
15 ll = 88
16 ff = partial(black.format_file_in_place, line_length=ll, fast=True)
17 fs = partial(black.format_str, line_length=ll)
18 THIS_FILE = Path(__file__)
19 THIS_DIR = THIS_FILE.parent
20 EMPTY_LINE = "# EMPTY LINE WITH WHITESPACE" + " (this comment will be removed)"
21
22
23 def dump_to_stderr(*output: str) -> str:
24     return "\n" + "\n".join(output) + "\n"
25
26
27 def read_data(name: str) -> Tuple[str, str]:
28     """read_data('test_name') -> 'input', 'output'"""
29     if not name.endswith((".py", ".out")):
30         name += ".py"
31     _input: List[str] = []
32     _output: List[str] = []
33     with open(THIS_DIR / name, "r", encoding="utf8") as test:
34         lines = test.readlines()
35     result = _input
36     for line in lines:
37         line = line.replace(EMPTY_LINE, "")
38         if line.rstrip() == "# output":
39             result = _output
40             continue
41
42         result.append(line)
43     if _input and not _output:
44         # If there's no output marker, treat the entire file as already pre-formatted.
45         _output = _input[:]
46     return "".join(_input).strip() + "\n", "".join(_output).strip() + "\n"
47
48
49 class BlackTestCase(unittest.TestCase):
50     maxDiff = None
51
52     def assertFormatEqual(self, expected: str, actual: str) -> None:
53         if actual != expected and not os.environ.get("SKIP_AST_PRINT"):
54             bdv: black.DebugVisitor[Any]
55             black.out("Expected tree:", fg="green")
56             try:
57                 exp_node = black.lib2to3_parse(expected)
58                 bdv = black.DebugVisitor()
59                 list(bdv.visit(exp_node))
60             except Exception as ve:
61                 black.err(str(ve))
62             black.out("Actual tree:", fg="red")
63             try:
64                 exp_node = black.lib2to3_parse(actual)
65                 bdv = black.DebugVisitor()
66                 list(bdv.visit(exp_node))
67             except Exception as ve:
68                 black.err(str(ve))
69         self.assertEqual(expected, actual)
70
71     @patch("black.dump_to_file", dump_to_stderr)
72     def test_self(self) -> None:
73         source, expected = read_data("test_black")
74         actual = fs(source)
75         self.assertFormatEqual(expected, actual)
76         black.assert_equivalent(source, actual)
77         black.assert_stable(source, actual, line_length=ll)
78         self.assertFalse(ff(THIS_FILE))
79
80     @patch("black.dump_to_file", dump_to_stderr)
81     def test_black(self) -> None:
82         source, expected = read_data("../black")
83         actual = fs(source)
84         self.assertFormatEqual(expected, actual)
85         black.assert_equivalent(source, actual)
86         black.assert_stable(source, actual, line_length=ll)
87         self.assertFalse(ff(THIS_DIR / ".." / "black.py"))
88
89     def test_piping(self) -> None:
90         source, expected = read_data("../black")
91         hold_stdin, hold_stdout = sys.stdin, sys.stdout
92         try:
93             sys.stdin, sys.stdout = StringIO(source), StringIO()
94             sys.stdin.name = "<stdin>"
95             black.format_stdin_to_stdout(line_length=ll, fast=True, write_back=True)
96             sys.stdout.seek(0)
97             actual = sys.stdout.read()
98         finally:
99             sys.stdin, sys.stdout = hold_stdin, hold_stdout
100         self.assertFormatEqual(expected, actual)
101         black.assert_equivalent(source, actual)
102         black.assert_stable(source, actual, line_length=ll)
103
104     @patch("black.dump_to_file", dump_to_stderr)
105     def test_setup(self) -> None:
106         source, expected = read_data("../setup")
107         actual = fs(source)
108         self.assertFormatEqual(expected, actual)
109         black.assert_equivalent(source, actual)
110         black.assert_stable(source, actual, line_length=ll)
111         self.assertFalse(ff(THIS_DIR / ".." / "setup.py"))
112
113     @patch("black.dump_to_file", dump_to_stderr)
114     def test_function(self) -> None:
115         source, expected = read_data("function")
116         actual = fs(source)
117         self.assertFormatEqual(expected, actual)
118         black.assert_equivalent(source, actual)
119         black.assert_stable(source, actual, line_length=ll)
120
121     @patch("black.dump_to_file", dump_to_stderr)
122     def test_expression(self) -> None:
123         source, expected = read_data("expression")
124         actual = fs(source)
125         self.assertFormatEqual(expected, actual)
126         black.assert_equivalent(source, actual)
127         black.assert_stable(source, actual, line_length=ll)
128
129     @patch("black.dump_to_file", dump_to_stderr)
130     def test_fstring(self) -> None:
131         source, expected = read_data("fstring")
132         actual = fs(source)
133         self.assertFormatEqual(expected, actual)
134         black.assert_equivalent(source, actual)
135         black.assert_stable(source, actual, line_length=ll)
136
137     @patch("black.dump_to_file", dump_to_stderr)
138     def test_string_quotes(self) -> None:
139         source, expected = read_data("string_quotes")
140         actual = fs(source)
141         self.assertFormatEqual(expected, actual)
142         black.assert_equivalent(source, actual)
143         black.assert_stable(source, actual, line_length=ll)
144
145     @patch("black.dump_to_file", dump_to_stderr)
146     def test_comments(self) -> None:
147         source, expected = read_data("comments")
148         actual = fs(source)
149         self.assertFormatEqual(expected, actual)
150         black.assert_equivalent(source, actual)
151         black.assert_stable(source, actual, line_length=ll)
152
153     @patch("black.dump_to_file", dump_to_stderr)
154     def test_comments2(self) -> None:
155         source, expected = read_data("comments2")
156         actual = fs(source)
157         self.assertFormatEqual(expected, actual)
158         black.assert_equivalent(source, actual)
159         black.assert_stable(source, actual, line_length=ll)
160
161     @patch("black.dump_to_file", dump_to_stderr)
162     def test_comments3(self) -> None:
163         source, expected = read_data("comments3")
164         actual = fs(source)
165         self.assertFormatEqual(expected, actual)
166         black.assert_equivalent(source, actual)
167         black.assert_stable(source, actual, line_length=ll)
168
169     @patch("black.dump_to_file", dump_to_stderr)
170     def test_comments4(self) -> None:
171         source, expected = read_data("comments4")
172         actual = fs(source)
173         self.assertFormatEqual(expected, actual)
174         black.assert_equivalent(source, actual)
175         black.assert_stable(source, actual, line_length=ll)
176
177     @patch("black.dump_to_file", dump_to_stderr)
178     def test_cantfit(self) -> None:
179         source, expected = read_data("cantfit")
180         actual = fs(source)
181         self.assertFormatEqual(expected, actual)
182         black.assert_equivalent(source, actual)
183         black.assert_stable(source, actual, line_length=ll)
184
185     @patch("black.dump_to_file", dump_to_stderr)
186     def test_import_spacing(self) -> None:
187         source, expected = read_data("import_spacing")
188         actual = fs(source)
189         self.assertFormatEqual(expected, actual)
190         black.assert_equivalent(source, actual)
191         black.assert_stable(source, actual, line_length=ll)
192
193     @patch("black.dump_to_file", dump_to_stderr)
194     def test_composition(self) -> None:
195         source, expected = read_data("composition")
196         actual = fs(source)
197         self.assertFormatEqual(expected, actual)
198         black.assert_equivalent(source, actual)
199         black.assert_stable(source, actual, line_length=ll)
200
201     @patch("black.dump_to_file", dump_to_stderr)
202     def test_empty_lines(self) -> None:
203         source, expected = read_data("empty_lines")
204         actual = fs(source)
205         self.assertFormatEqual(expected, actual)
206         black.assert_equivalent(source, actual)
207         black.assert_stable(source, actual, line_length=ll)
208
209     @patch("black.dump_to_file", dump_to_stderr)
210     def test_python2(self) -> None:
211         source, expected = read_data("python2")
212         actual = fs(source)
213         self.assertFormatEqual(expected, actual)
214         # black.assert_equivalent(source, actual)
215         black.assert_stable(source, actual, line_length=ll)
216
217     @patch("black.dump_to_file", dump_to_stderr)
218     def test_fmtonoff(self) -> None:
219         source, expected = read_data("fmtonoff")
220         actual = fs(source)
221         self.assertFormatEqual(expected, actual)
222         black.assert_equivalent(source, actual)
223         black.assert_stable(source, actual, line_length=ll)
224
225     def test_report(self) -> None:
226         report = black.Report()
227         out_lines = []
228         err_lines = []
229
230         def out(msg: str, **kwargs: Any) -> None:
231             out_lines.append(msg)
232
233         def err(msg: str, **kwargs: Any) -> None:
234             err_lines.append(msg)
235
236         with patch("black.out", out), patch("black.err", err):
237             report.done(Path("f1"), changed=False)
238             self.assertEqual(len(out_lines), 1)
239             self.assertEqual(len(err_lines), 0)
240             self.assertEqual(out_lines[-1], "f1 already well formatted, good job.")
241             self.assertEqual(unstyle(str(report)), "1 file left unchanged.")
242             self.assertEqual(report.return_code, 0)
243             report.done(Path("f2"), changed=True)
244             self.assertEqual(len(out_lines), 2)
245             self.assertEqual(len(err_lines), 0)
246             self.assertEqual(out_lines[-1], "reformatted f2")
247             self.assertEqual(
248                 unstyle(str(report)), "1 file reformatted, 1 file left unchanged."
249             )
250             self.assertEqual(report.return_code, 0)
251             report.check = True
252             self.assertEqual(report.return_code, 1)
253             report.check = False
254             report.failed(Path("e1"), "boom")
255             self.assertEqual(len(out_lines), 2)
256             self.assertEqual(len(err_lines), 1)
257             self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
258             self.assertEqual(
259                 unstyle(str(report)),
260                 "1 file reformatted, 1 file left unchanged, "
261                 "1 file failed to reformat.",
262             )
263             self.assertEqual(report.return_code, 123)
264             report.done(Path("f3"), changed=True)
265             self.assertEqual(len(out_lines), 3)
266             self.assertEqual(len(err_lines), 1)
267             self.assertEqual(out_lines[-1], "reformatted f3")
268             self.assertEqual(
269                 unstyle(str(report)),
270                 "2 files reformatted, 1 file left unchanged, "
271                 "1 file failed to reformat.",
272             )
273             self.assertEqual(report.return_code, 123)
274             report.failed(Path("e2"), "boom")
275             self.assertEqual(len(out_lines), 3)
276             self.assertEqual(len(err_lines), 2)
277             self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
278             self.assertEqual(
279                 unstyle(str(report)),
280                 "2 files reformatted, 1 file left unchanged, "
281                 "2 files failed to reformat.",
282             )
283             self.assertEqual(report.return_code, 123)
284             report.done(Path("f4"), changed=False)
285             self.assertEqual(len(out_lines), 4)
286             self.assertEqual(len(err_lines), 2)
287             self.assertEqual(out_lines[-1], "f4 already well formatted, good job.")
288             self.assertEqual(
289                 unstyle(str(report)),
290                 "2 files reformatted, 2 files left unchanged, "
291                 "2 files failed to reformat.",
292             )
293             self.assertEqual(report.return_code, 123)
294             report.check = True
295             self.assertEqual(
296                 unstyle(str(report)),
297                 "2 files would be reformatted, 2 files would be left unchanged, "
298                 "2 files would fail to reformat.",
299             )
300
301     def test_is_python36(self) -> None:
302         node = black.lib2to3_parse("def f(*, arg): ...\n")
303         self.assertFalse(black.is_python36(node))
304         node = black.lib2to3_parse("def f(*, arg,): ...\n")
305         self.assertTrue(black.is_python36(node))
306         node = black.lib2to3_parse("def f(*, arg): f'string'\n")
307         self.assertTrue(black.is_python36(node))
308         source, expected = read_data("function")
309         node = black.lib2to3_parse(source)
310         self.assertTrue(black.is_python36(node))
311         node = black.lib2to3_parse(expected)
312         self.assertTrue(black.is_python36(node))
313         source, expected = read_data("expression")
314         node = black.lib2to3_parse(source)
315         self.assertFalse(black.is_python36(node))
316         node = black.lib2to3_parse(expected)
317         self.assertFalse(black.is_python36(node))
318
319     def test_debug_visitor(self) -> None:
320         source, _ = read_data("debug_visitor.py")
321         expected, _ = read_data("debug_visitor.out")
322         out_lines = []
323         err_lines = []
324
325         def out(msg: str, **kwargs: Any) -> None:
326             out_lines.append(msg)
327
328         def err(msg: str, **kwargs: Any) -> None:
329             err_lines.append(msg)
330
331         with patch("black.out", out), patch("black.err", err):
332             black.DebugVisitor.show(source)
333         actual = "\n".join(out_lines) + "\n"
334         log_name = ""
335         if expected != actual:
336             log_name = black.dump_to_file(*out_lines)
337         self.assertEqual(
338             expected,
339             actual,
340             f"AST print out is different. Actual version dumped to {log_name}",
341         )
342
343
344 if __name__ == "__main__":
345     unittest.main()