Skip to content

Commit f115ae7

Browse files
samcunliffematt-grahampre-commit-ci[bot]paddyroddy
authored
DRY up the test code a bit. (#566)
- Remove `tmp_path` fixture from every test... - ...but then need to write a nested function for the fixture. - Also add `default_config` and `default_config_with` fixtures to help the cookiecutter generation. In the end it doesn't actually reduce the linecount (because I had to add to the docstrings). --------- Co-authored-by: Matt Graham <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Patrick J. Roddy <[email protected]>
1 parent f1a228d commit f115ae7

File tree

4 files changed

+76
-73
lines changed

4 files changed

+76
-73
lines changed

hooks/post_gen_project.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
6666
'-d "{{cookiecutter.project_short_description}}" '
6767
"--public "
6868
"-r origin "
69-
"--source {{cookiecutter.project_slug}}\n"
69+
"--source {{cookiecutter.project_slug}}\n",
7070
)
7171
except FileNotFoundError:
7272
# GitHub CLI isn't installed
@@ -78,7 +78,7 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
7878
"https://docs.github.com/en/get-started/quickstart/create-a-repo.\n\n"
7979
"Then run:\n\n"
8080
"git remote add origin [email protected]:"
81-
"{{cookiecutter.__repo_name}}.git\n"
81+
"{{cookiecutter.__repo_name}}.git\n",
8282
)
8383
except subprocess.CalledProcessError as e:
8484
# some other error
@@ -98,7 +98,7 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
9898
"{{cookiecutter.__repo_url}}/settings/pages\n\n"
9999
"and under 'Built and deployment' selecting 'Deploy from a branch' for "
100100
"the 'Source' drop-down and 'gh-pages' for the 'Branch' drop-down, "
101-
"leaving the branch path drop-down with its default value of '/ (root)'."
101+
"leaving the branch path drop-down with its default value of '/ (root)'.",
102102
)
103103

104104
return _EXIT_SUCCESS
@@ -109,5 +109,5 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
109109
main(
110110
"{{ cookiecutter.initialise_git_repository }}",
111111
"{{ cookiecutter.deploy_docs_to_github_pages }}",
112-
)
112+
),
113113
)

tests/conftest.py

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,50 @@
77
import pytest
88

99

10+
@pytest.fixture(scope="function") # noqa: PT003
11+
def default_config() -> dict[str, str]:
12+
"""
13+
Get the minimal default configuration for cutting a cookie in tests.
14+
15+
This is used if `generate_package` is called without arguments.
16+
"""
17+
return {
18+
"github_owner": "test-user",
19+
"project_short_description": "description",
20+
"project_name": "Cookiecutter Test",
21+
"project_slug": "cookiecutter-test",
22+
}
23+
24+
25+
@pytest.fixture(scope="function") # noqa: PT003
26+
def default_config_with(default_config: dict[str, str]) -> typing.Callable:
27+
"""Extend or modify the default configuration with one additional value."""
28+
29+
def _wrapped_with(**kwargs: str) -> dict[str, str]:
30+
return default_config | kwargs
31+
32+
return _wrapped_with
33+
34+
1035
def _generate_package(
1136
config: dict[str, str], path: pathlib.Path
12-
) -> subprocess.CompletedProcess[str]:
37+
) -> tuple[subprocess.CompletedProcess[str], pathlib.Path]:
1338
"""
1439
Generate a project from the cookiecutter template.
1540
16-
Arguments:
17-
---------
18-
config: dict
41+
Parameters
42+
----------
43+
config
1944
A dictionary with values for the cookiecutter template,
2045
as defined in the cookiecutter.json
21-
path: Path
46+
path
2247
Directory to create package in.
2348
49+
Returns
50+
-------
51+
subprocess.CompletedProcess, pathlib.Path
52+
The result of the cookiecutter command and the path to the generated package.
53+
2454
"""
2555
args = [f"{key}={val}" for key, val in config.items()]
2656
cmd = ["cookiecutter", ".", "--no-input", "--output-dir", f"{path}"]
@@ -30,10 +60,18 @@ def _generate_package(
3060
shell=False,
3161
capture_output=True,
3262
text=True,
33-
)
63+
), path / config["project_slug"]
3464

3565

3666
@pytest.fixture
37-
def generate_package() -> typing.Callable:
67+
def generate_package(
68+
default_config: dict[str, str], tmp_path: pathlib.Path
69+
) -> typing.Callable:
3870
"""Generate project from cookiecutter template."""
39-
return _generate_package
71+
72+
def _wrapped_with_tmp_path(
73+
config: dict[str, str] = default_config,
74+
) -> tuple[subprocess.CompletedProcess, pathlib.Path]:
75+
return _generate_package(config, tmp_path)
76+
77+
return _wrapped_with_tmp_path

tests/test_git_init.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
11
"""Checks that the git repo initialisation works."""
22

3-
import pathlib
43
import subprocess
54
import typing
65

76
import pytest
87

98

10-
@pytest.mark.parametrize("initialise_git_repository", [True, False])
9+
@pytest.mark.parametrize("init", [True, False])
1110
def test_initialisation_of_git_repo(
12-
initialise_git_repository: bool, # noqa: FBT001
11+
init: bool, # noqa: FBT001
12+
default_config_with: typing.Callable,
1313
generate_package: typing.Callable,
14-
tmp_path: pathlib.Path,
1514
) -> None:
1615
"""Checks to see if git was correctly initialised if desired."""
17-
test_config = {
18-
"github_owner": "test-user",
19-
"project_short_description": "description",
20-
"project_name": "Cookiecutter Test",
21-
"initialise_git_repository": initialise_git_repository,
22-
}
2316
# Run cookiecutter with initialise_git_repository
24-
result = generate_package(config=test_config, path=tmp_path)
25-
26-
test_project_dir = tmp_path / "cookiecutter-test"
17+
config = default_config_with(initialise_git_repository=str(init))
18+
result, test_project_dir = generate_package(config=config)
2719

2820
# check if git is initialised
2921
git_status = subprocess.run( # noqa: S603
@@ -37,7 +29,7 @@ def test_initialisation_of_git_repo(
3729
text=True,
3830
)
3931

40-
if not initialise_git_repository:
32+
if not init:
4133
# should not have found git
4234
assert "fatal: not a git repository" in git_status.stderr
4335
return # nothing more to test
@@ -57,9 +49,9 @@ def test_initialisation_of_git_repo(
5749
)
5850
assert (
5951
"GitHub CLI detected, you can create a repo with the following:\n\n"
60-
f"gh repo create {test_config['github_owner']}/"
52+
f"gh repo create {config['github_owner']}/"
6153
f"cookiecutter-test -d "
62-
f'"{test_config["project_short_description"]}" --public -r '
54+
f'"{config["project_short_description"]}" --public -r '
6355
f"origin --source cookiecutter-test" in result.stdout
6456
)
6557
except FileNotFoundError:
@@ -69,11 +61,11 @@ def test_initialisation_of_git_repo(
6961
assert (
7062
"You now have a local git repository. To sync this to GitHub you "
7163
"need to create an empty GitHub repo with the name "
72-
f"{test_config['github_owner']}/"
64+
f"{config['github_owner']}/"
7365
f"cookiecutter-test - DO NOT SELECT ANY "
7466
"OTHER OPTION.\n\nSee this link for more detail "
7567
"https://docs.github.com/en/get-started/quickstart/create-a-repo"
7668
".\n\nThen run:\n\ngit remote add origin [email protected]:"
77-
f"{test_config['github_owner']}/"
69+
f"{config['github_owner']}/"
7870
f"cookiecutter-test.git" in result.stdout
7971
)

tests/test_package_generation.py

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,19 @@ def get_all_files_folders(root_path: pathlib.Path) -> set[pathlib.Path]:
3636

3737

3838
def test_package_generation(
39-
tmp_path: pathlib.Path,
39+
default_config_with: typing.Callable,
4040
generate_package: typing.Callable,
4141
) -> None:
4242
"""Test package generation."""
43-
test_config = {
44-
"github_owner": "test-user",
45-
"project_short_description": "description",
46-
"project_name": "Cookiecutter Test",
47-
# Not having a git repo makes it easier to check in/out reference
48-
# data files to the main python-tooling git repository
49-
"initialise_git_repository": False,
50-
}
51-
generate_package(config=test_config, path=tmp_path)
43+
# Not having a git repo makes it easier to check in/out reference
44+
# data files to the main python-tooling git repository
45+
config = default_config_with(initialise_git_repository="False")
46+
_, test_project_dir = generate_package(config=config)
5247

5348
expected_package_dir = (
5449
pathlib.Path(__file__).parent / "data" / "test_package_generation"
5550
)
56-
# Check project directory exists
57-
test_project_dir = tmp_path / "cookiecutter-test"
58-
assert test_project_dir.exists()
51+
assert test_project_dir.exists(), "Project directory does not exist."
5952

6053
actual_files = get_all_files_folders(test_project_dir)
6154
expected_files = get_all_files_folders(expected_package_dir)
@@ -78,7 +71,7 @@ def test_package_generation(
7871
f2.readlines(),
7972
fromfile=str(actual_file),
8073
tofile=str(expected_file),
81-
)
74+
),
8275
)
8376

8477
if diff:
@@ -94,18 +87,11 @@ def test_package_generation(
9487

9588

9689
def test_pip_installable(
97-
tmp_path: pathlib.Path,
9890
venv: pytest_venv.VirtualEnvironment,
9991
generate_package: typing.Callable,
10092
) -> None:
10193
"""Test generated package is pip installable."""
102-
test_config = {
103-
"github_owner": "test-user",
104-
"project_short_description": "description",
105-
"project_name": "Cookiecutter Test",
106-
}
107-
generate_package(config=test_config, path=tmp_path)
108-
test_project_dir = tmp_path / "cookiecutter-test"
94+
_, test_project_dir = generate_package()
10995
# Try to install package in virtual environment with pip
11096
pipinstall = subprocess.run( # noqa: S603
11197
[
@@ -124,46 +110,33 @@ def test_pip_installable(
124110
)
125111

126112

127-
@pytest.mark.parametrize("funder", ["", "STFC"])
113+
@pytest.mark.parametrize("funder", ["", "STFC", "UKRI", "Wellcome Trust"])
128114
def test_optional_funder(
129-
tmp_path: pathlib.Path, generate_package: typing.Callable, funder: str
115+
funder: str,
116+
default_config_with: typing.Callable,
117+
generate_package: typing.Callable,
130118
) -> None:
131119
"""Test specifying funder or not in package generation."""
132-
config = {
133-
"github_owner": "test-user",
134-
"project_short_description": "description",
135-
"project_name": "Cookiecutter Test",
136-
"funder": funder,
137-
}
138-
139-
generate_package(config, tmp_path)
120+
config = default_config_with(funder=funder)
121+
_, test_project_dir = generate_package(config)
140122

141-
test_project_dir = tmp_path / "cookiecutter-test"
142123
with (test_project_dir / "README.md").open() as f:
143124
readme_text = "".join(f.readlines())
144125

145126
if funder == "":
146127
assert "## Acknowledgements" not in readme_text
147128
else:
148129
assert (
149-
f"## Acknowledgements\n\nThis work was funded by {config['funder']}."
150-
in readme_text
130+
f"## Acknowledgements\n\nThis work was funded by {funder}." in readme_text
151131
), readme_text
152132

153133

154134
def test_docs_build(
155-
tmp_path: pathlib.Path,
156135
venv: pytest_venv.VirtualEnvironment,
157136
generate_package: typing.Callable,
158137
) -> None:
159138
"""Test documentation build from package created from template."""
160-
config = {
161-
"github_owner": "test-user",
162-
"project_short_description": "description",
163-
"project_name": "Cookiecutter Test",
164-
}
165-
generate_package(config, tmp_path)
166-
test_project_dir = tmp_path / "cookiecutter-test"
139+
_, test_project_dir = generate_package()
167140
venv.install("tox")
168141
tox_docs_process = subprocess.run( # noqa: S603
169142
[

0 commit comments

Comments
 (0)