X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/9f096d55365cb63548eef97e254c2793ae2776a0..a80e037a9ad5867371d8df0cc8cc9c7520ccc020:/tests/test_black.py diff --git a/tests/test_black.py b/tests/test_black.py index 02926d1..08a3f31 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -11,6 +11,7 @@ from tempfile import TemporaryDirectory from typing import Any, List, Tuple, Iterator import unittest from unittest.mock import patch +import re from click import unstyle from click.testing import CliRunner @@ -31,7 +32,7 @@ def dump_to_stderr(*output: str) -> str: def read_data(name: str) -> Tuple[str, str]: """read_data('test_name') -> 'input', 'output'""" - if not name.endswith((".py", ".out", ".diff")): + if not name.endswith((".py", ".pyi", ".out", ".diff")): name += ".py" _input: List[str] = [] _output: List[str] = [] @@ -167,6 +168,14 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_function2(self) -> None: + source, expected = read_data("function2") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) def test_expression(self) -> None: source, expected = read_data("expression") @@ -228,6 +237,11 @@ class BlackTestCase(unittest.TestCase): self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + mode = black.FileMode.NO_STRING_NORMALIZATION + not_normalized = fs(source, mode=mode) + self.assertFormatEqual(source, not_normalized) + black.assert_equivalent(source, not_normalized) + black.assert_stable(source, not_normalized, line_length=ll, mode=mode) @patch("black.dump_to_file", dump_to_stderr) def test_slices(self) -> None: @@ -309,6 +323,14 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_string_prefixes(self) -> None: + source, expected = read_data("string_prefixes") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) def test_python2(self) -> None: source, expected = read_data("python2") @@ -317,6 +339,21 @@ class BlackTestCase(unittest.TestCase): # black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_python2_unicode_literals(self) -> None: + source, expected = read_data("python2_unicode_literals") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_stable(source, actual, line_length=ll) + + @patch("black.dump_to_file", dump_to_stderr) + def test_stub(self) -> None: + mode = black.FileMode.PYI + source, expected = read_data("stub.pyi") + actual = fs(source, mode=mode) + self.assertFormatEqual(expected, actual) + black.assert_stable(source, actual, line_length=ll, mode=mode) + @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff(self) -> None: source, expected = read_data("fmtonoff") @@ -325,6 +362,22 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_remove_empty_parentheses_after_class(self) -> None: + source, expected = read_data("class_blank_parentheses") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + + @patch("black.dump_to_file", dump_to_stderr) + def test_new_line_between_class_and_code(self) -> None: + source, expected = read_data("class_methods_new_line") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + def test_report(self) -> None: report = black.Report() out_lines = [] @@ -428,6 +481,28 @@ class BlackTestCase(unittest.TestCase): node = black.lib2to3_parse(expected) self.assertFalse(black.is_python36(node)) + def test_get_future_imports(self) -> None: + node = black.lib2to3_parse("\n") + self.assertEqual(set(), black.get_future_imports(node)) + node = black.lib2to3_parse("from __future__ import black\n") + self.assertEqual({"black"}, black.get_future_imports(node)) + node = black.lib2to3_parse("from __future__ import multiple, imports\n") + self.assertEqual({"multiple", "imports"}, black.get_future_imports(node)) + node = black.lib2to3_parse("from __future__ import (parenthesized, imports)\n") + self.assertEqual({"parenthesized", "imports"}, black.get_future_imports(node)) + node = black.lib2to3_parse( + "from __future__ import multiple\nfrom __future__ import imports\n" + ) + self.assertEqual({"multiple", "imports"}, black.get_future_imports(node)) + node = black.lib2to3_parse("# comment\nfrom __future__ import black\n") + self.assertEqual({"black"}, black.get_future_imports(node)) + node = black.lib2to3_parse('"""docstring"""\nfrom __future__ import black\n') + self.assertEqual({"black"}, black.get_future_imports(node)) + node = black.lib2to3_parse("some(other, code)\nfrom __future__ import black\n") + self.assertEqual(set(), black.get_future_imports(node)) + node = black.lib2to3_parse("from some.module import black\n") + self.assertEqual(set(), black.get_future_imports(node)) + def test_debug_visitor(self) -> None: source, _ = read_data("debug_visitor.py") expected, _ = read_data("debug_visitor.out") @@ -498,25 +573,27 @@ class BlackTestCase(unittest.TestCase): self.assertEqual("".join(err_lines), "") def test_cache_broken_file(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace: - cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH) + cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH, mode) with cache_file.open("w") as fobj: fobj.write("this is not a pickle") - self.assertEqual(black.read_cache(black.DEFAULT_LINE_LENGTH), {}) + self.assertEqual(black.read_cache(black.DEFAULT_LINE_LENGTH, mode), {}) src = (workspace / "test.py").resolve() with src.open("w") as fobj: fobj.write("print('hello')") result = CliRunner().invoke(black.main, [str(src)]) self.assertEqual(result.exit_code, 0) - cache = black.read_cache(black.DEFAULT_LINE_LENGTH) + cache = black.read_cache(black.DEFAULT_LINE_LENGTH, mode) self.assertIn(src, cache) def test_cache_single_file_already_cached(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace: src = (workspace / "test.py").resolve() with src.open("w") as fobj: fobj.write("print('hello')") - black.write_cache({}, [src], black.DEFAULT_LINE_LENGTH) + black.write_cache({}, [src], black.DEFAULT_LINE_LENGTH, mode) result = CliRunner().invoke(black.main, [str(src)]) self.assertEqual(result.exit_code, 0) with src.open("r") as fobj: @@ -524,6 +601,7 @@ class BlackTestCase(unittest.TestCase): @event_loop(close=False) def test_cache_multiple_files(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace, patch( "black.ProcessPoolExecutor", new=ThreadPoolExecutor ): @@ -533,44 +611,48 @@ class BlackTestCase(unittest.TestCase): two = (workspace / "two.py").resolve() with two.open("w") as fobj: fobj.write("print('hello')") - black.write_cache({}, [one], black.DEFAULT_LINE_LENGTH) + black.write_cache({}, [one], black.DEFAULT_LINE_LENGTH, mode) result = CliRunner().invoke(black.main, [str(workspace)]) self.assertEqual(result.exit_code, 0) with one.open("r") as fobj: self.assertEqual(fobj.read(), "print('hello')") with two.open("r") as fobj: self.assertEqual(fobj.read(), 'print("hello")\n') - cache = black.read_cache(black.DEFAULT_LINE_LENGTH) + cache = black.read_cache(black.DEFAULT_LINE_LENGTH, mode) self.assertIn(one, cache) self.assertIn(two, cache) def test_no_cache_when_writeback_diff(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace: src = (workspace / "test.py").resolve() with src.open("w") as fobj: fobj.write("print('hello')") result = CliRunner().invoke(black.main, [str(src), "--diff"]) self.assertEqual(result.exit_code, 0) - cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH) + cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH, mode) self.assertFalse(cache_file.exists()) def test_no_cache_when_stdin(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir(): result = CliRunner().invoke(black.main, ["-"], input="print('hello')") self.assertEqual(result.exit_code, 0) - cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH) + cache_file = black.get_cache_file(black.DEFAULT_LINE_LENGTH, mode) self.assertFalse(cache_file.exists()) def test_read_cache_no_cachefile(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir(): - self.assertEqual(black.read_cache(black.DEFAULT_LINE_LENGTH), {}) + self.assertEqual(black.read_cache(black.DEFAULT_LINE_LENGTH, mode), {}) def test_write_cache_read_cache(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace: src = (workspace / "test.py").resolve() src.touch() - black.write_cache({}, [src], black.DEFAULT_LINE_LENGTH) - cache = black.read_cache(black.DEFAULT_LINE_LENGTH) + black.write_cache({}, [src], black.DEFAULT_LINE_LENGTH, mode) + cache = black.read_cache(black.DEFAULT_LINE_LENGTH, mode) self.assertIn(src, cache) self.assertEqual(cache[src], black.get_cache_info(src)) @@ -591,13 +673,15 @@ class BlackTestCase(unittest.TestCase): self.assertEqual(done, [cached]) def test_write_cache_creates_directory_if_needed(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir(exists=False) as workspace: self.assertFalse(workspace.exists()) - black.write_cache({}, [], black.DEFAULT_LINE_LENGTH) + black.write_cache({}, [], black.DEFAULT_LINE_LENGTH, mode) self.assertTrue(workspace.exists()) @event_loop(close=False) def test_failed_formatting_does_not_get_cached(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace, patch( "black.ProcessPoolExecutor", new=ThreadPoolExecutor ): @@ -609,15 +693,17 @@ class BlackTestCase(unittest.TestCase): fobj.write('print("hello")\n') result = CliRunner().invoke(black.main, [str(workspace)]) self.assertEqual(result.exit_code, 123) - cache = black.read_cache(black.DEFAULT_LINE_LENGTH) + cache = black.read_cache(black.DEFAULT_LINE_LENGTH, mode) self.assertNotIn(failing, cache) self.assertIn(clean, cache) def test_write_cache_write_fail(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir(), patch.object(Path, "open") as mock: mock.side_effect = OSError - black.write_cache({}, [], black.DEFAULT_LINE_LENGTH) + black.write_cache({}, [], black.DEFAULT_LINE_LENGTH, mode) + @event_loop(close=False) def test_check_diff_use_together(self) -> None: with cache_dir(): # Files which will be reformatted. @@ -634,18 +720,196 @@ class BlackTestCase(unittest.TestCase): result = CliRunner().invoke( black.main, [str(src1), str(src2), "--diff", "--check"] ) - self.assertEqual(result.exit_code, 1) + self.assertEqual(result.exit_code, 1, result.output) + + def test_no_files(self) -> None: + with cache_dir(): + # Without an argument, black exits with error code 0. + result = CliRunner().invoke(black.main, []) + self.assertEqual(result.exit_code, 0) + + def test_broken_symlink(self) -> None: + with cache_dir() as workspace: + symlink = workspace / "broken_link.py" + symlink.symlink_to("nonexistent.py") + result = CliRunner().invoke(black.main, [str(workspace.resolve())]) + self.assertEqual(result.exit_code, 0) def test_read_cache_line_lengths(self) -> None: + mode = black.FileMode.AUTO_DETECT with cache_dir() as workspace: path = (workspace / "file.py").resolve() path.touch() - black.write_cache({}, [path], 1) - one = black.read_cache(1) + black.write_cache({}, [path], 1, mode) + one = black.read_cache(1, mode) self.assertIn(path, one) - two = black.read_cache(2) + two = black.read_cache(2, mode) self.assertNotIn(path, two) + def test_single_file_force_pyi(self) -> None: + reg_mode = black.FileMode.AUTO_DETECT + pyi_mode = black.FileMode.PYI + contents, expected = read_data("force_pyi") + with cache_dir() as workspace: + path = (workspace / "file.py").resolve() + with open(path, "w") as fh: + fh.write(contents) + result = CliRunner().invoke(black.main, [str(path), "--pyi"]) + self.assertEqual(result.exit_code, 0) + with open(path, "r") as fh: + actual = fh.read() + # verify cache with --pyi is separate + pyi_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, pyi_mode) + self.assertIn(path, pyi_cache) + normal_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, reg_mode) + self.assertNotIn(path, normal_cache) + self.assertEqual(actual, expected) + + @event_loop(close=False) + def test_multi_file_force_pyi(self) -> None: + reg_mode = black.FileMode.AUTO_DETECT + pyi_mode = black.FileMode.PYI + contents, expected = read_data("force_pyi") + with cache_dir() as workspace: + paths = [ + (workspace / "file1.py").resolve(), + (workspace / "file2.py").resolve(), + ] + for path in paths: + with open(path, "w") as fh: + fh.write(contents) + result = CliRunner().invoke(black.main, [str(p) for p in paths] + ["--pyi"]) + self.assertEqual(result.exit_code, 0) + for path in paths: + with open(path, "r") as fh: + actual = fh.read() + self.assertEqual(actual, expected) + # verify cache with --pyi is separate + pyi_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, pyi_mode) + normal_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, reg_mode) + for path in paths: + self.assertIn(path, pyi_cache) + self.assertNotIn(path, normal_cache) + + def test_pipe_force_pyi(self) -> None: + source, expected = read_data("force_pyi") + result = CliRunner().invoke(black.main, ["-", "-q", "--pyi"], input=source) + self.assertEqual(result.exit_code, 0) + actual = result.output + self.assertFormatEqual(actual, expected) + + def test_single_file_force_py36(self) -> None: + reg_mode = black.FileMode.AUTO_DETECT + py36_mode = black.FileMode.PYTHON36 + source, expected = read_data("force_py36") + with cache_dir() as workspace: + path = (workspace / "file.py").resolve() + with open(path, "w") as fh: + fh.write(source) + result = CliRunner().invoke(black.main, [str(path), "--py36"]) + self.assertEqual(result.exit_code, 0) + with open(path, "r") as fh: + actual = fh.read() + # verify cache with --py36 is separate + py36_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, py36_mode) + self.assertIn(path, py36_cache) + normal_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, reg_mode) + self.assertNotIn(path, normal_cache) + self.assertEqual(actual, expected) + + @event_loop(close=False) + def test_multi_file_force_py36(self) -> None: + reg_mode = black.FileMode.AUTO_DETECT + py36_mode = black.FileMode.PYTHON36 + source, expected = read_data("force_py36") + with cache_dir() as workspace: + paths = [ + (workspace / "file1.py").resolve(), + (workspace / "file2.py").resolve(), + ] + for path in paths: + with open(path, "w") as fh: + fh.write(source) + result = CliRunner().invoke( + black.main, [str(p) for p in paths] + ["--py36"] + ) + self.assertEqual(result.exit_code, 0) + for path in paths: + with open(path, "r") as fh: + actual = fh.read() + self.assertEqual(actual, expected) + # verify cache with --py36 is separate + pyi_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, py36_mode) + normal_cache = black.read_cache(black.DEFAULT_LINE_LENGTH, reg_mode) + for path in paths: + self.assertIn(path, pyi_cache) + self.assertNotIn(path, normal_cache) + + def test_pipe_force_py36(self) -> None: + source, expected = read_data("force_py36") + result = CliRunner().invoke(black.main, ["-", "-q", "--py36"], input=source) + self.assertEqual(result.exit_code, 0) + actual = result.output + self.assertFormatEqual(actual, expected) + + def test_include_exclude(self) -> None: + path = THIS_DIR / "include_exclude_tests" + include = re.compile(r"\.pyi?$") + exclude = re.compile(r"/exclude/|/\.definitely_exclude/") + sources: List[Path] = [] + expected = [ + Path(THIS_DIR / "include_exclude_tests/b/dont_exclude/a.py"), + Path(THIS_DIR / "include_exclude_tests/b/dont_exclude/a.pyi"), + ] + sources.extend(black.gen_python_files_in_dir(path, include, exclude)) + self.assertEqual(sorted(expected), sorted(sources)) + + def test_empty_include(self) -> None: + path = THIS_DIR / "include_exclude_tests" + empty = re.compile(r"") + sources: List[Path] = [] + expected = [ + Path(path / "b/exclude/a.pie"), + Path(path / "b/exclude/a.py"), + Path(path / "b/exclude/a.pyi"), + Path(path / "b/dont_exclude/a.pie"), + Path(path / "b/dont_exclude/a.py"), + Path(path / "b/dont_exclude/a.pyi"), + Path(path / "b/.definitely_exclude/a.pie"), + Path(path / "b/.definitely_exclude/a.py"), + Path(path / "b/.definitely_exclude/a.pyi"), + ] + sources.extend( + black.gen_python_files_in_dir( + path, empty, re.compile(black.DEFAULT_EXCLUDES) + ) + ) + self.assertEqual(sorted(expected), sorted(sources)) + + def test_empty_exclude(self) -> None: + path = THIS_DIR / "include_exclude_tests" + empty = re.compile(r"") + sources: List[Path] = [] + expected = [ + Path(path / "b/dont_exclude/a.py"), + Path(path / "b/dont_exclude/a.pyi"), + Path(path / "b/exclude/a.py"), + Path(path / "b/exclude/a.pyi"), + Path(path / "b/.definitely_exclude/a.py"), + Path(path / "b/.definitely_exclude/a.pyi"), + ] + sources.extend( + black.gen_python_files_in_dir( + path, re.compile(black.DEFAULT_INCLUDES), empty + ) + ) + self.assertEqual(sorted(expected), sorted(sources)) + + def test_invalid_include_exclude(self) -> None: + for option in ["--include", "--exclude"]: + result = CliRunner().invoke(black.main, ["-", option, "**()(!!*)"]) + self.assertEqual(result.exit_code, 2) + if __name__ == "__main__": unittest.main()