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

8e739063f6e50c908105cfab832df1b7c2dc4445
[etc/vim.git] / tests / test_blackd.py
1 import re
2 import sys
3 from typing import Any
4 from unittest.mock import patch
5
6 import pytest
7 from click.testing import CliRunner
8
9 from tests.util import DETERMINISTIC_HEADER, read_data
10
11 LESS_THAN_311 = sys.version_info < (3, 11)
12
13 if LESS_THAN_311:  # noqa: C901
14     try:
15         from aiohttp import web
16         from aiohttp.test_utils import AioHTTPTestCase
17
18         import blackd
19     except ImportError as e:
20         raise RuntimeError("Please install Black with the 'd' extra") from e
21
22     try:
23         from aiohttp.test_utils import unittest_run_loop
24     except ImportError:
25         # unittest_run_loop is unnecessary and a no-op since aiohttp 3.8, and aiohttp 4
26         # removed it. To maintain compatibility we can make our own no-op decorator.
27         def unittest_run_loop(func: Any, *args: Any, **kwargs: Any) -> Any:
28             return func
29
30     @pytest.mark.blackd
31     class BlackDTestCase(AioHTTPTestCase):
32         def test_blackd_main(self) -> None:
33             with patch("blackd.web.run_app"):
34                 result = CliRunner().invoke(blackd.main, [])
35                 if result.exception is not None:
36                     raise result.exception
37                 self.assertEqual(result.exit_code, 0)
38
39         async def get_application(self) -> web.Application:
40             return blackd.make_app()
41
42         @unittest_run_loop
43         async def test_blackd_request_needs_formatting(self) -> None:
44             response = await self.client.post("/", data=b"print('hello world')")
45             self.assertEqual(response.status, 200)
46             self.assertEqual(response.charset, "utf8")
47             self.assertEqual(await response.read(), b'print("hello world")\n')
48
49         @unittest_run_loop
50         async def test_blackd_request_no_change(self) -> None:
51             response = await self.client.post("/", data=b'print("hello world")\n')
52             self.assertEqual(response.status, 204)
53             self.assertEqual(await response.read(), b"")
54
55         @unittest_run_loop
56         async def test_blackd_request_syntax_error(self) -> None:
57             response = await self.client.post("/", data=b"what even ( is")
58             self.assertEqual(response.status, 400)
59             content = await response.text()
60             self.assertTrue(
61                 content.startswith("Cannot parse"),
62                 msg=f"Expected error to start with 'Cannot parse', got {repr(content)}",
63             )
64
65         @unittest_run_loop
66         async def test_blackd_unsupported_version(self) -> None:
67             response = await self.client.post(
68                 "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "2"}
69             )
70             self.assertEqual(response.status, 501)
71
72         @unittest_run_loop
73         async def test_blackd_supported_version(self) -> None:
74             response = await self.client.post(
75                 "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "1"}
76             )
77             self.assertEqual(response.status, 200)
78
79         @unittest_run_loop
80         async def test_blackd_invalid_python_variant(self) -> None:
81             async def check(header_value: str, expected_status: int = 400) -> None:
82                 response = await self.client.post(
83                     "/",
84                     data=b"what",
85                     headers={blackd.PYTHON_VARIANT_HEADER: header_value},
86                 )
87                 self.assertEqual(response.status, expected_status)
88
89             await check("lol")
90             await check("ruby3.5")
91             await check("pyi3.6")
92             await check("py1.5")
93             await check("2")
94             await check("2.7")
95             await check("py2.7")
96             await check("2.8")
97             await check("py2.8")
98             await check("3.0")
99             await check("pypy3.0")
100             await check("jython3.4")
101
102         @unittest_run_loop
103         async def test_blackd_pyi(self) -> None:
104             source, expected = read_data("miscellaneous", "stub.pyi")
105             response = await self.client.post(
106                 "/", data=source, headers={blackd.PYTHON_VARIANT_HEADER: "pyi"}
107             )
108             self.assertEqual(response.status, 200)
109             self.assertEqual(await response.text(), expected)
110
111         @unittest_run_loop
112         async def test_blackd_diff(self) -> None:
113             diff_header = re.compile(
114                 r"(In|Out)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
115             )
116
117             source, _ = read_data("miscellaneous", "blackd_diff")
118             expected, _ = read_data("miscellaneous", "blackd_diff.diff")
119
120             response = await self.client.post(
121                 "/", data=source, headers={blackd.DIFF_HEADER: "true"}
122             )
123             self.assertEqual(response.status, 200)
124
125             actual = await response.text()
126             actual = diff_header.sub(DETERMINISTIC_HEADER, actual)
127             self.assertEqual(actual, expected)
128
129         @unittest_run_loop
130         async def test_blackd_python_variant(self) -> None:
131             code = (
132                 "def f(\n"
133                 "    and_has_a_bunch_of,\n"
134                 "    very_long_arguments_too,\n"
135                 "    and_lots_of_them_as_well_lol,\n"
136                 "    **and_very_long_keyword_arguments\n"
137                 "):\n"
138                 "    pass\n"
139             )
140
141             async def check(header_value: str, expected_status: int) -> None:
142                 response = await self.client.post(
143                     "/", data=code, headers={blackd.PYTHON_VARIANT_HEADER: header_value}
144                 )
145                 self.assertEqual(
146                     response.status, expected_status, msg=await response.text()
147                 )
148
149             await check("3.6", 200)
150             await check("py3.6", 200)
151             await check("3.6,3.7", 200)
152             await check("3.6,py3.7", 200)
153             await check("py36,py37", 200)
154             await check("36", 200)
155             await check("3.6.4", 200)
156             await check("3.4", 204)
157             await check("py3.4", 204)
158             await check("py34,py36", 204)
159             await check("34", 204)
160
161         @unittest_run_loop
162         async def test_blackd_line_length(self) -> None:
163             response = await self.client.post(
164                 "/", data=b'print("hello")\n', headers={blackd.LINE_LENGTH_HEADER: "7"}
165             )
166             self.assertEqual(response.status, 200)
167
168         @unittest_run_loop
169         async def test_blackd_invalid_line_length(self) -> None:
170             response = await self.client.post(
171                 "/",
172                 data=b'print("hello")\n',
173                 headers={blackd.LINE_LENGTH_HEADER: "NaN"},
174             )
175             self.assertEqual(response.status, 400)
176
177         @unittest_run_loop
178         async def test_blackd_preview(self) -> None:
179             response = await self.client.post(
180                 "/", data=b'print("hello")\n', headers={blackd.PREVIEW: "true"}
181             )
182             self.assertEqual(response.status, 204)
183
184         @unittest_run_loop
185         async def test_blackd_response_black_version_header(self) -> None:
186             response = await self.client.post("/")
187             self.assertIsNotNone(response.headers.get(blackd.BLACK_VERSION_HEADER))
188
189         @unittest_run_loop
190         async def test_cors_preflight(self) -> None:
191             response = await self.client.options(
192                 "/",
193                 headers={
194                     "Access-Control-Request-Method": "POST",
195                     "Origin": "*",
196                     "Access-Control-Request-Headers": "Content-Type",
197                 },
198             )
199             self.assertEqual(response.status, 200)
200             self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
201             self.assertIsNotNone(response.headers.get("Access-Control-Allow-Headers"))
202             self.assertIsNotNone(response.headers.get("Access-Control-Allow-Methods"))
203
204         @unittest_run_loop
205         async def test_cors_headers_present(self) -> None:
206             response = await self.client.post("/", headers={"Origin": "*"})
207             self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
208             self.assertIsNotNone(response.headers.get("Access-Control-Expose-Headers"))