Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove hard coded test cases #3062

Merged
merged 16 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
43 changes: 6 additions & 37 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,6 @@
all_data_cases,
)

PY310_CASES: List[str] = [
"starred_for_target",
"pattern_matching_simple",
"pattern_matching_complex",
"pattern_matching_extras",
"pattern_matching_style",
"pattern_matching_generic",
"parenthesized_context_managers",
]

PY311_CASES: List[str] = [
"pep_654",
"pep_654_style",
]

PREVIEW_CASES: List[str] = [
# string processing
"cantfit",
"comments7",
"comments8",
"long_strings",
"long_strings__edge_case",
"long_strings__regression",
"percent_precedence",
"remove_except_parens",
"remove_for_brackets",
"one_element_subscript",
"remove_await_parens",
"return_annotation_brackets",
"docstring_preview",
]

SOURCES: List[str] = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also walk the source directories here and get all of the Python files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the right thing to do is to add the following step/job to the CI process:

pip install -e .
black --check src

This should not be a unit test in my opinion, but another step/job in the CI process.

If you want an example, see what I did for my tool Statue in the CI process.
In the end of the CI I added a step called "Run on self" that checks that the code of statue pass the static code analysis ran by statue.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, it appears we only check each file with default params, so that would work. I don't have a strong preference for it being in tests or CI. Perhaps here before publishing test results, so that the whole version matrix is tested. Other opinions?

"src/black/__init__.py",
"src/black/__main__.py",
Expand Down Expand Up @@ -105,7 +73,7 @@ def test_simple_format(filename: str) -> None:
check_file(filename, DEFAULT_MODE)


@pytest.mark.parametrize("filename", PREVIEW_CASES)
@pytest.mark.parametrize("filename", all_data_cases("preview"))
def test_preview_format(filename: str) -> None:
check_file(filename, black.Mode(preview=True))

Expand Down Expand Up @@ -164,15 +132,16 @@ def test_remove_with_brackets() -> None:
)


@pytest.mark.parametrize("filename", PY310_CASES)
@pytest.mark.parametrize("filename", all_data_cases("py_310"))
def test_python_310(filename: str) -> None:
source, expected = read_data(filename)
mode = black.Mode(target_versions={black.TargetVersion.PY310})
assert_format(source, expected, mode, minimum_version=(3, 10))


def test_python_310_without_target_version() -> None:
source, expected = read_data("pattern_matching_simple")
@pytest.mark.parametrize("filename", all_data_cases("py_310"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting that this changed, but I guess it can't hurt to test all the cases!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that this is the right thing to do, because the test is not specific for "pattern_matching_simple"

def test_python_310_without_target_version(filename: str) -> None:
source, expected = read_data(filename)
mode = black.Mode()
assert_format(source, expected, mode, minimum_version=(3, 10))

Expand All @@ -186,7 +155,7 @@ def test_patma_invalid() -> None:
exc_info.match("Cannot parse: 10:11")


@pytest.mark.parametrize("filename", PY311_CASES)
@pytest.mark.parametrize("filename", all_data_cases("py_311"))
def test_python_311(filename: str) -> None:
source, expected = read_data(filename)
mode = black.Mode(target_versions={black.TargetVersion.PY311})
Expand Down
37 changes: 14 additions & 23 deletions tests/test_ipynb.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import pytest
from black import Mode
from _pytest.monkeypatch import MonkeyPatch
from tests.util import DATA_DIR
from tests.util import DATA_DIR, read_jupyter_notebook, get_case_path

with contextlib.suppress(ModuleNotFoundError):
import IPython
Expand Down Expand Up @@ -252,9 +252,7 @@ def test_empty_cell() -> None:


def test_entire_notebook_empty_metadata() -> None:
with open(DATA_DIR / "notebook_empty_metadata.ipynb", "rb") as fd:
content_bytes = fd.read()
content = content_bytes.decode()
content = read_jupyter_notebook("notebook_empty_metadata.ipynb")
felix-hilden marked this conversation as resolved.
Show resolved Hide resolved
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
Expand Down Expand Up @@ -289,9 +287,7 @@ def test_entire_notebook_empty_metadata() -> None:


def test_entire_notebook_trailing_newline() -> None:
with open(DATA_DIR / "notebook_trailing_newline.ipynb", "rb") as fd:
content_bytes = fd.read()
content = content_bytes.decode()
content = read_jupyter_notebook("notebook_trailing_newline.ipynb")
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
Expand Down Expand Up @@ -338,9 +334,7 @@ def test_entire_notebook_trailing_newline() -> None:


def test_entire_notebook_no_trailing_newline() -> None:
with open(DATA_DIR / "notebook_no_trailing_newline.ipynb", "rb") as fd:
content_bytes = fd.read()
content = content_bytes.decode()
content = read_jupyter_notebook("notebook_no_trailing_newline.ipynb")
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
Expand Down Expand Up @@ -387,17 +381,14 @@ def test_entire_notebook_no_trailing_newline() -> None:


def test_entire_notebook_without_changes() -> None:
with open(DATA_DIR / "notebook_without_changes.ipynb", "rb") as fd:
content_bytes = fd.read()
content = content_bytes.decode()
content = read_jupyter_notebook("notebook_without_changes.ipynb")
with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)


def test_non_python_notebook() -> None:
with open(DATA_DIR / "non_python_notebook.ipynb", "rb") as fd:
content_bytes = fd.read()
content = content_bytes.decode()
content = read_jupyter_notebook("non_python_notebook.ipynb")

with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)

Expand All @@ -408,7 +399,7 @@ def test_empty_string() -> None:


def test_unparseable_notebook() -> None:
path = DATA_DIR / "notebook_which_cant_be_parsed.ipynb"
path = get_case_path("notebook_which_cant_be_parsed.ipynb")
msg = rf"File '{re.escape(str(path))}' cannot be parsed as valid Jupyter notebook\."
with pytest.raises(ValueError, match=msg):
format_file_in_place(path, fast=True, mode=JUPYTER_MODE)
Expand All @@ -418,7 +409,7 @@ def test_ipynb_diff_with_change() -> None:
result = runner.invoke(
main,
[
str(DATA_DIR / "notebook_trailing_newline.ipynb"),
str(get_case_path("notebook_trailing_newline.ipynb")),
"--diff",
f"--config={EMPTY_CONFIG}",
],
Expand All @@ -431,7 +422,7 @@ def test_ipynb_diff_with_no_change() -> None:
result = runner.invoke(
main,
[
str(DATA_DIR / "notebook_without_changes.ipynb"),
str(get_case_path("notebook_without_changes.ipynb")),
"--diff",
f"--config={EMPTY_CONFIG}",
],
Expand All @@ -445,7 +436,7 @@ def test_cache_isnt_written_if_no_jupyter_deps_single(
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
nb = DATA_DIR / "notebook_trailing_newline.ipynb"
nb = get_case_path("notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.ipynb"
with open(nb) as src, open(tmp_nb, "w") as dst:
dst.write(src.read())
Expand All @@ -471,7 +462,7 @@ def test_cache_isnt_written_if_no_jupyter_deps_dir(
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
nb = DATA_DIR / "notebook_trailing_newline.ipynb"
nb = get_case_path("notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.ipynb"
with open(nb) as src, open(tmp_nb, "w") as dst:
dst.write(src.read())
Expand All @@ -489,7 +480,7 @@ def test_cache_isnt_written_if_no_jupyter_deps_dir(


def test_ipynb_flag(tmp_path: pathlib.Path) -> None:
nb = DATA_DIR / "notebook_trailing_newline.ipynb"
nb = get_case_path("notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.a_file_extension_which_is_definitely_not_ipynb"
with open(nb) as src, open(tmp_nb, "w") as dst:
dst.write(src.read())
Expand All @@ -507,7 +498,7 @@ def test_ipynb_flag(tmp_path: pathlib.Path) -> None:


def test_ipynb_and_pyi_flags() -> None:
nb = DATA_DIR / "notebook_trailing_newline.ipynb"
nb = get_case_path("notebook_trailing_newline.ipynb")
result = runner.invoke(
main,
[
Expand Down
7 changes: 3 additions & 4 deletions tests/test_no_ipynb.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import pytest
import os
import pathlib

from tests.util import THIS_DIR
from tests.util import get_case_path
from black import main, jupyter_dependencies_are_installed
from click.testing import CliRunner

Expand All @@ -13,7 +12,7 @@

def test_ipynb_diff_with_no_change_single() -> None:
jupyter_dependencies_are_installed.cache_clear()
path = THIS_DIR / "data/notebook_trailing_newline.ipynb"
path = get_case_path("notebook_trailing_newline.ipynb")
result = runner.invoke(main, [str(path)])
expected_output = (
"Skipping .ipynb files as Jupyter dependencies are not installed.\n"
Expand All @@ -25,7 +24,7 @@ def test_ipynb_diff_with_no_change_single() -> None:
def test_ipynb_diff_with_no_change_dir(tmp_path: pathlib.Path) -> None:
jupyter_dependencies_are_installed.cache_clear()
runner = CliRunner()
nb = os.path.join("tests", "data", "notebook_trailing_newline.ipynb")
nb = get_case_path("notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.ipynb"
with open(nb) as src, open(tmp_nb, "w") as dst:
dst.write(src.read())
Expand Down
23 changes: 19 additions & 4 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,19 @@ def all_data_cases(dir_name: str, data: bool = True) -> List[str]:
return [f"{dir_name}/{case_path.stem}" for case_path in cases_dir.iterdir()]


def read_data(name: str, data: bool = True) -> Tuple[str, str]:
"""read_data('test_name') -> 'input', 'output'"""
if not name.endswith((".py", ".pyi", ".out", ".diff")):
def get_case_path(name: str, data: bool = True) -> Path:
"""Get case path from name"""
if not name.endswith((".py", ".pyi", ".out", ".diff", ".ipynb")):
name += ".py"
base_dir = DATA_DIR if data else PROJECT_ROOT
case_path = base_dir / name
assert case_path.is_file(), f"{case_path} is not a file."
return read_data_from_file(case_path)
return case_path


def read_data(name: str, data: bool = True) -> Tuple[str, str]:
"""read_data('test_name') -> 'input', 'output'"""
return read_data_from_file(get_case_path(name, data))


def read_data_from_file(file_name: Path) -> Tuple[str, str]:
Expand All @@ -126,6 +131,16 @@ def read_data_from_file(file_name: Path) -> Tuple[str, str]:
return "".join(_input).strip() + "\n", "".join(_output).strip() + "\n"


def read_jupyter_notebook(name: str, data: bool = True) -> str:
return read_jupyter_notebook_from_file(get_case_path(name, data))


def read_jupyter_notebook_from_file(file_name: Path) -> str:
with open(file_name, mode="rb") as fd:
content_bytes = fd.read()
return content_bytes.decode()


@contextmanager
def change_directory(path: Path) -> Iterator[None]:
"""Context manager to temporarily chdir to a different directory."""
Expand Down