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

Speed up parameterized tests which use Git #761

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
74a1449
test: speed up `test_black_options`
akaihola Oct 20, 2024
d72faa8
feat: use Darkgraylib feature branch during development
akaihola Oct 21, 2024
5e17649
test: speed up `test_black_config_file_and_options`
akaihola Oct 29, 2024
9e69758
test: speed up `test_black_config_file_and_options`
akaihola Nov 4, 2024
9ba2629
test: speed up `test_options`
akaihola Nov 4, 2024
19516ec
test: speed up `test_git_get_modified_python_files`
akaihola Nov 4, 2024
2e373e8
test: speed up `test_main_retval`
akaihola Nov 4, 2024
0d6ca32
test: speed up `test_revision`
akaihola Nov 4, 2024
8c5b4f6
test: add `unix_and_windows_newline_repos` helper
akaihola Nov 9, 2024
fe44692
test: speed up `test_format_edited_parts`
akaihola Nov 4, 2024
736f540
test: speed up `test_main`
akaihola Nov 5, 2024
6d89050
test: speed up `test_git_exists_in_revision` and `test_get_missing_at…
akaihola Nov 5, 2024
44cc853
test: speed up `test_main_stdin_filename_repo`
akaihola Nov 8, 2024
498dd27
test: speed up `test_apply_isort`
akaihola Nov 8, 2024
18cda2f
test: speed up `test_apply_isort_exclude`
akaihola Nov 8, 2024
75b5290
test: speed up `test_build_isort_args`
akaihola Nov 8, 2024
9c6b82c
test: speed up `test_main_historical_ok`
akaihola Nov 9, 2024
2086e12
test: speed up `test_git_get_modified_python_files`
akaihola Nov 9, 2024
8a91ad7
test: speed up `test_reformat_and_flynt_single_file`
akaihola Nov 9, 2024
f846d0e
test: speed up `test_format_edited_parts_stdin`
akaihola Nov 9, 2024
ee707ef
test: speed up `test_flynt_single_file`
akaihola Nov 9, 2024
82f0d0d
test: speed up `test_format_edited_parts_historical`
akaihola Nov 9, 2024
67af390
test: speed up `test_edited_linenums_differ_compare_revisions` and `t…
akaihola Nov 9, 2024
4610eaf
test: speed up `test_edited_linenums_differ_revision_vs_lines_multili…
akaihola Nov 9, 2024
9db0a6a
test: speed up `test_main_isort.py`
akaihola Nov 16, 2024
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
3 changes: 2 additions & 1 deletion .github/workflows/mypy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ jobs:
with:
python-version: 3.x
- run: |
# TODO: change to darkgraylib.git@main before merging
uv pip install --system -U \
black \
git+https://github.com/akaihola/darkgraylib.git@main \
git+https://github.com/akaihola/darkgraylib.git@module-scope-git-repo-fixture \
flynt \
isort \
mypy>=0.990 \
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ jobs:
python-version: 3.x
- name: Install dependencies for running Pylint
run: |
# TODO: change to darkgraylib.git@main before merging
uv pip install --system -U \
black \
git+https://github.com/akaihola/darkgraylib.git@main \
git+https://github.com/akaihola/darkgraylib.git@module-scope-git-repo-fixture \
defusedxml \
pygments \
'pylint<=3.2.7' \
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ignore = [
"ANN001", # Missing type annotation for function argument
"ANN201", # Missing return type annotation for public function
"ANN204", # Missing return type annotation for special method `__init__`
"ARG001", # Unused function argument
"C408", # Unnecessary `dict` call (rewrite as a literal)
"PLR0913", # Too many arguments in function definition (n > 5)
"S101", # Use of `assert` detected
Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ packages = find:
install_requires =
# NOTE: remember to keep `constraints-oldest.txt` in sync with these
black>=22.3.0
darkgraylib~=2.0.1
# TODO: change to `darkgraylib~=2.1.0` before merging
darkgraylib @ git+https://github.com/akaihola/darkgraylib@module-scope-git-repo-fixture
toml>=0.10.0
typing_extensions>=4.0.1
# NOTE: remember to keep `.github/workflows/python-package.yml` in sync
Expand Down
23 changes: 23 additions & 0 deletions src/darker/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Configuration and fixtures for the Pytest based test suite."""

import pytest

try:
from black.files import _load_toml
except ImportError:
# Black 24.1.1 and earlier don't have `_load_toml`.
_load_toml = None # type: ignore[assignment]


@pytest.fixture
def load_toml_cache_clear() -> None:
"""Clear LRU caching in `black.files._load_toml` before each test.

To use this on all test cases in a test module, add this to the top::

pytestmark = pytest.mark.usefixtures("load_toml_cache_clear")

"""
if _load_toml:
# Black 24.1.1 and earlier don't have `_load_toml`, so no LRU cache to clear.
_load_toml.cache_clear()
11 changes: 11 additions & 0 deletions src/darker/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from typing import Generator, Optional
from unittest.mock import patch

from darkgraylib.testtools.git_repo_plugin import GitRepoFixture


@contextmanager
def _package_present(
Expand Down Expand Up @@ -43,3 +45,12 @@ def flynt_present(present: bool) -> Generator[None, None, None]:
fake_flynt_module.code_editor = ModuleType("process") # type: ignore
fake_flynt_module.code_editor.fstringify_code_by_line = None # type: ignore
yield


@contextmanager
def unix_and_windows_newline_repos(request, tmp_path_factory):
"""Create temporary repositories for Unix and windows newlines separately."""
with GitRepoFixture.context(
request, tmp_path_factory
) as repo_unix, GitRepoFixture.context(request, tmp_path_factory) as repo_windows:
yield {"\n": repo_unix, "\r\n": repo_windows}
114 changes: 77 additions & 37 deletions src/darker/tests/test_command_line.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# pylint: disable=too-many-arguments,too-many-locals,use-dict-literal
"""Unit tests for `darker.command_line` and `darker.__main__`."""

"""Unit tests for :mod:`darker.command_line` and :mod:`darker.__main__`"""
# pylint: disable=too-many-arguments,too-many-locals
# pylint: disable=no-member,redefined-outer-name,unused-argument,use-dict-literal

from __future__ import annotations

import os
import re
Expand All @@ -22,10 +25,14 @@
from darker.tests.helpers import flynt_present, isort_present
from darkgraylib.config import ConfigurationError
from darkgraylib.git import RevisionRange
from darkgraylib.testtools.git_repo_plugin import GitRepoFixture
from darkgraylib.testtools.helpers import raises_if_exception
from darkgraylib.utils import TextDocument, joinlines

pytestmark = pytest.mark.usefixtures("find_project_root_cache_clear")
# Clear LRU caches for `find_project_root()` and `_load_toml()` before each test
pytestmark = pytest.mark.usefixtures(
"find_project_root_cache_clear", "load_toml_cache_clear"
)


@pytest.mark.kwparametrize(
Expand Down Expand Up @@ -444,6 +451,24 @@ def test_help_with_flynt_package(capsys):
)


@pytest.fixture(scope="module")
def black_options_files(request, tmp_path_factory):
"""Fixture for the `test_black_options` test."""
with GitRepoFixture.context(request, tmp_path_factory) as repo:
(repo.root / "pyproject.toml").write_bytes(b"[tool.black]\n")
(repo.root / "black.cfg").write_text(
dedent(
"""
[tool.black]
line-length = 81
skip-string-normalization = false
target-version = 'py38'
"""
)
)
yield repo.add({"main.py": 'print("Hello World!")\n'}, commit="Initial commit")


@pytest.mark.kwparametrize(
dict(options=[], expect=call()),
dict(
Expand Down Expand Up @@ -528,34 +553,35 @@ def test_help_with_flynt_package(capsys):
),
),
)
def test_black_options(monkeypatch, tmpdir, git_repo, options, expect):
"""Black options from the command line are passed correctly to Black"""
monkeypatch.chdir(tmpdir)
(tmpdir / "pyproject.toml").write("[tool.black]\n")
(tmpdir / "black.cfg").write(
dedent(
"""
[tool.black]
line-length = 81
skip-string-normalization = false
target-version = 'py38'
"""
)
)
added_files = git_repo.add(
{"main.py": 'print("Hello World!")\n'}, commit="Initial commit"
)
added_files["main.py"].write_bytes(b'print ("Hello World!")\n')
def test_black_options(black_options_files, options, expect):
"""Black options from the command line are passed correctly to Black."""
# The Git repository set up by the module-scope `black_options_repo` fixture is
# shared by all test cases. The "main.py" file modified by the test run needs to be
# reset to its original content before the next test case.
black_options_files["main.py"].write_bytes(b'print ("Hello World!")\n')
with patch.object(
black_formatter, "Mode", wraps=black_formatter.Mode
) as file_mode_class:

main(options + [str(path) for path in added_files.values()])
main(options + [str(path) for path in black_options_files.values()])

assert black_options_files["main.py"].read_bytes() == b'print("Hello World!")\n'
_, expect_args, expect_kwargs = expect
file_mode_class.assert_called_once_with(*expect_args, **expect_kwargs)


@pytest.fixture(scope="module")
def black_config_file_and_options_files(request, tmp_path_factory):
"""Git repository fixture for the `test_black_config_file_and_options` test."""
with GitRepoFixture.context(request, tmp_path_factory) as repo:
repo_files = repo.add(
{"main.py": "foo", "pyproject.toml": "* placeholder, will be overwritten"},
commit="Initial commit",
)
repo_files["main.py"].write_bytes(b"a = [1, 2,]")
yield repo_files


@pytest.mark.kwparametrize(
dict(config=[], options=[], expect=call()),
dict(
Expand Down Expand Up @@ -654,23 +680,33 @@ def test_black_options(monkeypatch, tmpdir, git_repo, options, expect):
expect=call(preview=True),
),
)
def test_black_config_file_and_options(git_repo, config, options, expect):
def test_black_config_file_and_options(
black_config_file_and_options_files, config, options, expect
):
"""Black configuration file and command line options are combined correctly"""
added_files = git_repo.add(
{"main.py": "foo", "pyproject.toml": joinlines(["[tool.black]"] + config)},
commit="Initial commit",
)
added_files["main.py"].write_bytes(b"a = [1, 2,]")
repo_files = black_config_file_and_options_files
repo_files["pyproject.toml"].write_text(joinlines(["[tool.black]", *config]))
mode_class_mock = Mock(wraps=black_formatter.Mode)
# Speed up tests by mocking `format_str` to skip running Black
format_str = Mock(return_value="a = [1, 2,]")
with patch.multiple(black_formatter, Mode=mode_class_mock, format_str=format_str):

main(options + [str(path) for path in added_files.values()])
main(options + [str(path) for path in repo_files.values()])

assert mode_class_mock.call_args_list == [expect]


@pytest.fixture(scope="module")
def options_repo(request, tmp_path_factory):
"""Git repository fixture for the `test_options` test."""
with GitRepoFixture.context(request, tmp_path_factory) as repo:
paths = repo.add(
{"a.py": "1\n", "b.py": "2\n", "my.cfg": ""}, commit="Initial commit"
)
paths["a.py"].write_bytes(b"one\n")
yield repo


@pytest.mark.kwparametrize(
dict(
options=["a.py"],
Expand Down Expand Up @@ -755,41 +791,45 @@ def test_black_config_file_and_options(git_repo, config, options, expect):
),
),
)
def test_options(git_repo, options, expect):
def test_options(options_repo, monkeypatch, options, expect):
"""The main engine is called with correct parameters based on the command line

Executed in a clean directory so Darker's own ``pyproject.toml`` doesn't interfere.

"""
paths = git_repo.add(
{"a.py": "1\n", "b.py": "2\n", "my.cfg": ""}, commit="Initial commit"
)
paths["a.py"].write_bytes(b"one\n")
with patch('darker.__main__.format_edited_parts') as format_edited_parts:
monkeypatch.chdir(options_repo.root)

retval = main(options)

expect_formatter = BlackFormatter()
expect_formatter.config = expect[4]
actual_formatter = format_edited_parts.call_args.args[4]
assert actual_formatter.config == expect_formatter.config
expect = (Path(git_repo.root), expect[1]) + expect[2:4] + (expect_formatter,)
expect = (Path(options_repo.root), expect[1]) + expect[2:4] + (expect_formatter,)
format_edited_parts.assert_called_once_with(
*expect, report_unmodified=False, workers=1
)
assert retval == 0


@pytest.fixture(scope="module")
def main_retval_repo(request, tmp_path_factory):
"""Git repository fixture for the `test_main_retval` test."""
with GitRepoFixture.context(request, tmp_path_factory) as repo:
repo.add({"a.py": ""}, commit="Initial commit")
yield


@pytest.mark.kwparametrize(
dict(arguments=["a.py"], changes=False),
dict(arguments=["a.py"], changes=True),
dict(arguments=["--check", "a.py"], changes=False),
dict(arguments=["--check", "a.py"], changes=True, expect_retval=1),
expect_retval=0,
)
def test_main_retval(git_repo, arguments, changes, expect_retval):
def test_main_retval(main_retval_repo, arguments, changes, expect_retval):
"""``main()`` return value is correct based on ``--check`` and reformatting."""
git_repo.add({"a.py": ""}, commit="Initial commit")
format_edited_parts = Mock()
format_edited_parts.return_value = (
[
Expand Down
Loading
Loading