Skip to content

Commit 76cdd51

Browse files
committed
Swap DEFAULT_CONFIG global dict to a function-scoped fixture.
Also add a default_config_with fixture for default plus one change (the main use case in our parametrised tests).
1 parent b1e8ad0 commit 76cdd51

4 files changed

Lines changed: 106 additions & 94 deletions

File tree

tests/conftest.py

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,73 @@
66

77
import pytest
88

9-
from .helpers import DEFAULT_CONFIG, _generate_package # type: ignore[import-not-found]
9+
10+
@pytest.fixture
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
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(key: str, value: str) -> dict[str, str]:
30+
default_config[key] = value
31+
return default_config
32+
33+
return _wrapped_with
34+
35+
36+
def _generate_package(
37+
config: dict[str, str], path: pathlib.Path
38+
) -> tuple[subprocess.CompletedProcess[str], pathlib.Path]:
39+
"""
40+
Generate a project from the cookiecutter template.
41+
42+
Parameters
43+
----------
44+
config
45+
A dictionary with values for the cookiecutter template,
46+
as defined in the cookiecutter.json
47+
path
48+
Directory to create package in.
49+
50+
Returns
51+
-------
52+
subprocess.CompletedProcess, pathlib.Path
53+
The result of the cookiecutter command and the path to the generated package.
54+
55+
"""
56+
args = [f"{key}={val}" for key, val in config.items()]
57+
cmd = ["cookiecutter", ".", "--no-input", "--output-dir", f"{path}"]
58+
return subprocess.run( # noqa: S603
59+
cmd + args,
60+
check=False,
61+
shell=False,
62+
capture_output=True,
63+
text=True,
64+
), path / config["project_slug"]
1065

1166

1267
@pytest.fixture
13-
def generate_package(tmp_path: pathlib.Path) -> typing.Callable:
68+
def generate_package(
69+
default_config: dict[str, str], tmp_path: pathlib.Path
70+
) -> typing.Callable:
1471
"""Generate project from cookiecutter template."""
1572

16-
def wrapped_with_tmp_path(
17-
config: dict[str, str] = DEFAULT_CONFIG,
73+
def _wrapped_with_tmp_path(
74+
config: dict[str, str] = default_config,
1875
) -> tuple[subprocess.CompletedProcess, pathlib.Path]:
1976
return _generate_package(config, tmp_path)
2077

21-
return wrapped_with_tmp_path
78+
return _wrapped_with_tmp_path

tests/helpers.py

Lines changed: 0 additions & 67 deletions
This file was deleted.

tests/test_git_init.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@
55

66
import pytest
77

8-
from .helpers import DEFAULT_CONFIG # type: ignore[import-not-found]
9-
108

119
@pytest.mark.parametrize("initialise_git_repository", [True, False])
1210
def test_initialisation_of_git_repo(
1311
initialise_git_repository: bool, # noqa: FBT001
12+
default_config_with: typing.Callable,
1413
generate_package: typing.Callable,
1514
) -> None:
1615
"""Checks to see if git was correctly initialised if desired."""
17-
test_config = DEFAULT_CONFIG.copy()
18-
test_config["initialise_git_repository"] = str(initialise_git_repository)
16+
config = default_config_with(
17+
"initialise_git_repository", str(initialise_git_repository)
18+
)
19+
1920
# Run cookiecutter with initialise_git_repository
20-
result, test_project_dir = generate_package(config=test_config)
21+
result, test_project_dir = generate_package(config=config)
2122

2223
# check if git is initialised
2324
git_status = subprocess.run( # noqa: S603
@@ -51,9 +52,9 @@ def test_initialisation_of_git_repo(
5152
)
5253
assert (
5354
"GitHub CLI detected, you can create a repo with the following:\n\n"
54-
f"gh repo create {test_config['github_owner']}/"
55+
f"gh repo create {config['github_owner']}/"
5556
f"cookiecutter-test -d "
56-
f'"{test_config["project_short_description"]}" --public -r '
57+
f'"{config["project_short_description"]}" --public -r '
5758
f"origin --source cookiecutter-test" in result.stdout
5859
)
5960
except FileNotFoundError:
@@ -63,11 +64,11 @@ def test_initialisation_of_git_repo(
6364
assert (
6465
"You now have a local git repository. To sync this to GitHub you "
6566
"need to create an empty GitHub repo with the name "
66-
f"{test_config['github_owner']}/"
67+
f"{config['github_owner']}/"
6768
f"cookiecutter-test - DO NOT SELECT ANY "
6869
"OTHER OPTION.\n\nSee this link for more detail "
6970
"https://docs.github.com/en/get-started/quickstart/create-a-repo"
7071
".\n\nThen run:\n\ngit remote add origin [email protected]:"
71-
f"{test_config['github_owner']}/"
72+
f"{config['github_owner']}/"
7273
f"cookiecutter-test.git" in result.stdout
7374
)

tests/test_package_generation.py

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Checks that the cookiecutter works."""
22

33
import difflib
4+
import os
45
import pathlib
56
import shutil
67
import subprocess
@@ -9,19 +10,39 @@
910
import pytest
1011
import pytest_venv # type: ignore[import-not-found]
1112

12-
from .helpers import ( # type: ignore[import-not-found]
13-
DEFAULT_CONFIG,
14-
get_all_files_folders,
15-
)
1613

14+
def get_all_files_folders(root_path: pathlib.Path) -> set[pathlib.Path]:
15+
"""
16+
Get all files and folders under a directory.
1717
18-
def test_package_generation(generate_package: typing.Callable) -> None:
18+
The paths are returned relative to the root path given.
19+
__pycache__ directories and .DS_Store files are ignored.
20+
"""
21+
file_set: set[pathlib.Path] = set()
22+
for dirpath, _, filenames in os.walk(root_path):
23+
dirpath_path = pathlib.Path(dirpath).relative_to(root_path)
24+
if dirpath_path.name in ["__pycache__"]:
25+
continue
26+
27+
# Add this directory
28+
file_set.update((dirpath_path,))
29+
# Add any files in it
30+
for filename in filenames:
31+
if filename in [".DS_Store"]:
32+
continue
33+
file_set.update((dirpath_path / filename,))
34+
35+
return file_set
36+
37+
38+
def test_package_generation(
39+
default_config_with: typing.Callable, generate_package: typing.Callable
40+
) -> None:
1941
"""Test package generation."""
20-
test_config = DEFAULT_CONFIG.copy()
2142
# Not having a git repo makes it easier to check in/out reference
2243
# data files to the main python-tooling git repository
23-
test_config["initialise_git_repository"] = "False"
24-
_, test_project_dir = generate_package(config=test_config)
44+
config = default_config_with("initialise_git_repository", "False")
45+
_, test_project_dir = generate_package(config=config)
2546

2647
expected_package_dir = (
2748
pathlib.Path(__file__).parent / "data" / "test_package_generation"
@@ -89,10 +110,11 @@ def test_pip_installable(
89110

90111

91112
@pytest.mark.parametrize("funder", ["", "STFC", "UKRI", "Wellcome Trust"])
92-
def test_optional_funder(generate_package: typing.Callable, funder: str) -> None:
113+
def test_optional_funder(
114+
funder: str, default_config_with: typing.Callable, generate_package: typing.Callable
115+
) -> None:
93116
"""Test specifying funder or not in package generation."""
94-
config = DEFAULT_CONFIG.copy()
95-
config["funder"] = funder
117+
config = default_config_with("funder", funder)
96118
_, test_project_dir = generate_package(config)
97119

98120
with (test_project_dir / "README.md").open() as f:
@@ -102,8 +124,7 @@ def test_optional_funder(generate_package: typing.Callable, funder: str) -> None
102124
assert "## Acknowledgements" not in readme_text
103125
else:
104126
assert (
105-
f"## Acknowledgements\n\nThis work was funded by {config['funder']}."
106-
in readme_text
127+
f"## Acknowledgements\n\nThis work was funded by {funder}." in readme_text
107128
), readme_text
108129

109130

0 commit comments

Comments
 (0)