X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/204f76e0c02a12aeccb3ab708fe41f7e95435a29..cf75673e1a2c993025a2113ce194d5c65f311c85:/tests/test_black.py diff --git a/tests/test_black.py b/tests/test_black.py index 7d855ca..098a9ec 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -6,7 +6,7 @@ from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager from dataclasses import replace import inspect -from io import BytesIO, TextIOWrapper +from io import BytesIO import os from pathlib import Path from platform import system @@ -16,10 +16,8 @@ from tempfile import TemporaryDirectory import types from typing import ( Any, - BinaryIO, Callable, Dict, - Generator, List, Iterator, TypeVar, @@ -34,6 +32,10 @@ from click.testing import CliRunner import black from black import Feature, TargetVersion +from black.cache import get_cache_file +from black.debug import DebugVisitor +from black.report import Report +import black.files from pathspec import PathSpec @@ -48,7 +50,6 @@ from tests.util import ( ff, dump_to_stderr, ) -from .test_primer import PrimerCLITests # noqa: F401 THIS_FILE = Path(__file__) @@ -69,7 +70,7 @@ def cache_dir(exists: bool = True) -> Iterator[Path]: cache_dir = Path(workspace) if not exists: cache_dir = cache_dir / "new" - with patch("black.CACHE_DIR", cache_dir): + with patch("black.cache.CACHE_DIR", cache_dir): yield cache_dir @@ -100,28 +101,10 @@ class FakeParameter(click.Parameter): class BlackRunner(CliRunner): - """Modify CliRunner so that stderr is not merged with stdout. - - This is a hack that can be removed once we depend on Click 7.x""" + """Make sure STDOUT and STDERR are kept separate when testing Black via its CLI.""" def __init__(self) -> None: - self.stderrbuf = BytesIO() - self.stdoutbuf = BytesIO() - self.stdout_bytes = b"" - self.stderr_bytes = b"" - super().__init__() - - @contextmanager - def isolation(self, *args: Any, **kwargs: Any) -> Generator[BinaryIO, None, None]: - with super().isolation(*args, **kwargs) as output: - try: - hold_stderr = sys.stderr - sys.stderr = TextIOWrapper(self.stderrbuf, encoding=self.charset) - yield output - finally: - self.stdout_bytes = sys.stdout.buffer.getvalue() # type: ignore - self.stderr_bytes = sys.stderr.buffer.getvalue() # type: ignore - sys.stderr = hold_stderr + super().__init__(mix_stderr=False) class BlackTestCase(BlackBaseTestCase): @@ -137,8 +120,8 @@ class BlackTestCase(BlackBaseTestCase): exit_code, msg=( f"Failed with args: {args}\n" - f"stdout: {runner.stdout_bytes.decode()!r}\n" - f"stderr: {runner.stderr_bytes.decode()!r}\n" + f"stdout: {result.stdout_bytes.decode()!r}\n" + f"stderr: {result.stderr_bytes.decode()!r}\n" f"exception: {result.exception}" ), ) @@ -171,8 +154,9 @@ class BlackTestCase(BlackBaseTestCase): ) self.assertEqual(result.exit_code, 0) self.assertFormatEqual(expected, result.output) - black.assert_equivalent(source, result.output) - black.assert_stable(source, result.output, DEFAULT_MODE) + if source != result.output: + black.assert_equivalent(source, result.output) + black.assert_stable(source, result.output, DEFAULT_MODE) def test_piping_diff(self) -> None: diff_header = re.compile( @@ -460,11 +444,15 @@ class BlackTestCase(BlackBaseTestCase): ) self.assertEqual(expected, actual, msg) - @pytest.mark.without_python2 + @pytest.mark.no_python2 def test_python2_should_fail_without_optional_install(self) -> None: - # python 3.7 and below will install typed-ast and will be able to parse Python 2 if sys.version_info < (3, 8): - return + self.skipTest( + "Python 3.6 and 3.7 will install typed-ast to work and as such will be" + " able to parse Python 2 syntax without explicitly specifying the" + " python2 extra" + ) + source = "x = 1234l" tmp_file = Path(black.dump_to_file(source)) try: @@ -474,7 +462,7 @@ class BlackTestCase(BlackBaseTestCase): finally: os.unlink(tmp_file) actual = ( - runner.stderr_bytes.decode() + result.stderr_bytes.decode() .replace("\n", "") .replace("\\n", "") .replace("\\r", "") @@ -578,7 +566,7 @@ class BlackTestCase(BlackBaseTestCase): self.assertFormatEqual(contents_spc, fs(contents_tab)) def test_report_verbose(self) -> None: - report = black.Report(verbose=True) + report = Report(verbose=True) out_lines = [] err_lines = [] @@ -588,7 +576,7 @@ class BlackTestCase(BlackBaseTestCase): def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) - with patch("black.out", out), patch("black.err", err): + with patch("black.output._out", out), patch("black.output._err", err): report.done(Path("f1"), black.Changed.NO) self.assertEqual(len(out_lines), 1) self.assertEqual(len(err_lines), 0) @@ -680,7 +668,7 @@ class BlackTestCase(BlackBaseTestCase): ) def test_report_quiet(self) -> None: - report = black.Report(quiet=True) + report = Report(quiet=True) out_lines = [] err_lines = [] @@ -690,7 +678,7 @@ class BlackTestCase(BlackBaseTestCase): def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) - with patch("black.out", out), patch("black.err", err): + with patch("black.output._out", out), patch("black.output._err", err): report.done(Path("f1"), black.Changed.NO) self.assertEqual(len(out_lines), 0) self.assertEqual(len(err_lines), 0) @@ -784,7 +772,7 @@ class BlackTestCase(BlackBaseTestCase): def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) - with patch("black.out", out), patch("black.err", err): + with patch("black.output._out", out), patch("black.output._err", err): report.done(Path("f1"), black.Changed.NO) self.assertEqual(len(out_lines), 0) self.assertEqual(len(err_lines), 0) @@ -1001,8 +989,8 @@ class BlackTestCase(BlackBaseTestCase): def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) - with patch("black.out", out), patch("black.err", err): - black.DebugVisitor.show(source) + with patch("black.debug.out", out): + DebugVisitor.show(source) actual = "\n".join(out_lines) + "\n" log_name = "" if expected != actual: @@ -1050,7 +1038,7 @@ class BlackTestCase(BlackBaseTestCase): def err(msg: str, **kwargs: Any) -> None: err_lines.append(msg) - with patch("black.out", out), patch("black.err", err): + with patch("black.output._out", out), patch("black.output._err", err): with self.assertRaises(AssertionError): self.assertFormatEqual("j = [1, 2, 3]", "j = [1, 2, 3,]") @@ -1062,7 +1050,7 @@ class BlackTestCase(BlackBaseTestCase): def test_cache_broken_file(self) -> None: mode = DEFAULT_MODE with cache_dir() as workspace: - cache_file = black.get_cache_file(mode) + cache_file = get_cache_file(mode) with cache_file.open("w") as fobj: fobj.write("this is not a pickle") self.assertEqual(black.read_cache(mode), {}) @@ -1116,7 +1104,7 @@ class BlackTestCase(BlackBaseTestCase): "black.write_cache" ) as write_cache: self.invokeBlack([str(src), "--diff"]) - cache_file = black.get_cache_file(mode) + cache_file = get_cache_file(mode) self.assertFalse(cache_file.exists()) write_cache.assert_not_called() read_cache.assert_not_called() @@ -1131,7 +1119,7 @@ class BlackTestCase(BlackBaseTestCase): "black.write_cache" ) as write_cache: self.invokeBlack([str(src), "--diff", "--color"]) - cache_file = black.get_cache_file(mode) + cache_file = get_cache_file(mode) self.assertFalse(cache_file.exists()) write_cache.assert_not_called() read_cache.assert_not_called() @@ -1169,7 +1157,7 @@ class BlackTestCase(BlackBaseTestCase): black.main, ["-"], input=BytesIO(b"print('hello')") ) self.assertEqual(result.exit_code, 0) - cache_file = black.get_cache_file(mode) + cache_file = get_cache_file(mode) self.assertFalse(cache_file.exists()) def test_read_cache_no_cachefile(self) -> None: @@ -1418,6 +1406,32 @@ class BlackTestCase(BlackBaseTestCase): ) self.assertEqual(sorted(expected), sorted(sources)) + def test_gitignore_used_as_default(self) -> None: + path = Path(THIS_DIR / "data" / "include_exclude_tests") + include = re.compile(r"\.pyi?$") + extend_exclude = re.compile(r"/exclude/") + src = str(path / "b/") + report = black.Report() + expected: List[Path] = [ + path / "b/.definitely_exclude/a.py", + path / "b/.definitely_exclude/a.pyi", + ] + sources = list( + black.get_sources( + ctx=FakeContext(), + src=(src,), + quiet=True, + verbose=False, + include=include, + exclude=None, + extend_exclude=extend_exclude, + force_exclude=None, + report=report, + stdin_filename=None, + ) + ) + self.assertEqual(sorted(expected), sorted(sources)) + @patch("black.find_project_root", lambda *args: THIS_DIR.resolve()) def test_exclude_for_issue_1572(self) -> None: # Exclude shouldn't touch files that were explicitly given to Black through the @@ -1494,7 +1508,7 @@ class BlackTestCase(BlackBaseTestCase): @patch("black.find_project_root", lambda *args: THIS_DIR.resolve()) def test_get_sources_with_stdin_filename_and_exclude(self) -> None: - # Exclude shouldn't exclude stdin_filename since it is mimicing the + # Exclude shouldn't exclude stdin_filename since it is mimicking the # file being passed directly. This is the same as # test_exclude_for_issue_1572 path = THIS_DIR / "data" / "include_exclude_tests" @@ -1689,6 +1703,33 @@ class BlackTestCase(BlackBaseTestCase): ) self.assertEqual(sorted(expected), sorted(sources)) + def test_nested_gitignore(self) -> None: + path = Path(THIS_DIR / "data" / "nested_gitignore_tests") + include = re.compile(r"\.pyi?$") + exclude = re.compile(r"") + root_gitignore = black.files.get_gitignore(path) + report = black.Report() + expected: List[Path] = [ + Path(path / "x.py"), + Path(path / "root/b.py"), + Path(path / "root/c.py"), + Path(path / "root/child/c.py"), + ] + this_abs = THIS_DIR.resolve() + sources = list( + black.gen_python_files( + path.iterdir(), + this_abs, + include, + exclude, + None, + None, + report, + root_gitignore, + ) + ) + self.assertEqual(sorted(expected), sorted(sources)) + def test_empty_include(self) -> None: path = THIS_DIR / "data" / "include_exclude_tests" report = black.Report() @@ -1705,6 +1746,8 @@ class BlackTestCase(BlackBaseTestCase): Path(path / "b/.definitely_exclude/a.pie"), Path(path / "b/.definitely_exclude/a.py"), Path(path / "b/.definitely_exclude/a.pyi"), + Path(path / ".gitignore"), + Path(path / "pyproject.toml"), ] this_abs = THIS_DIR.resolve() sources.extend( @@ -1769,7 +1812,7 @@ class BlackTestCase(BlackBaseTestCase): black.main, ["-", "--fast"], input=BytesIO(contents.encode("utf8")) ) self.assertEqual(result.exit_code, 0) - output = runner.stdout_bytes + output = result.stdout_bytes self.assertIn(nl.encode("utf8"), output) if nl == "\n": self.assertNotIn(b"\r\n", output) @@ -1868,7 +1911,7 @@ class BlackTestCase(BlackBaseTestCase): critical=fail, log=fail, ): - ff(THIS_FILE) + ff(THIS_DIR / "util.py") def test_invalid_config_return_code(self) -> None: tmp_file = Path(black.dump_to_file()) @@ -1928,7 +1971,10 @@ class BlackTestCase(BlackBaseTestCase): self.assertEqual(black.find_project_root((src_dir,)), src_dir.resolve()) self.assertEqual(black.find_project_root((src_python,)), src_dir.resolve()) - @patch("black.find_user_pyproject_toml", black.find_user_pyproject_toml.__wrapped__) + @patch( + "black.files.find_user_pyproject_toml", + black.files.find_user_pyproject_toml.__wrapped__, + ) def test_find_user_pyproject_toml_linux(self) -> None: if system() == "Windows": return @@ -1938,7 +1984,7 @@ class BlackTestCase(BlackBaseTestCase): tmp_user_config = Path(workspace) / "black" with patch.dict("os.environ", {"XDG_CONFIG_HOME": workspace}): self.assertEqual( - black.find_user_pyproject_toml(), tmp_user_config.resolve() + black.files.find_user_pyproject_toml(), tmp_user_config.resolve() ) # Test fallback for XDG_CONFIG_HOME @@ -1946,7 +1992,7 @@ class BlackTestCase(BlackBaseTestCase): os.environ.pop("XDG_CONFIG_HOME", None) fallback_user_config = Path("~/.config").expanduser() / "black" self.assertEqual( - black.find_user_pyproject_toml(), fallback_user_config.resolve() + black.files.find_user_pyproject_toml(), fallback_user_config.resolve() ) def test_find_user_pyproject_toml_windows(self) -> None: @@ -1954,7 +2000,9 @@ class BlackTestCase(BlackBaseTestCase): return user_config_path = Path.home() / ".black" - self.assertEqual(black.find_user_pyproject_toml(), user_config_path.resolve()) + self.assertEqual( + black.files.find_user_pyproject_toml(), user_config_path.resolve() + ) def test_bpo_33660_workaround(self) -> None: if system() == "Windows":