Skip to content

wip: restructure testing #1196

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

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

### changed

- refine activation logic and add unittest for the relevant cases instead of trying to speedrun setuptools
- refine activation logic and add unittest for the relevant cases instead of trying to speedrun setuptools

## v9.1.1

Expand Down
6 changes: 5 additions & 1 deletion src/setuptools_scm/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
from setuptools_scm import Configuration
from setuptools_scm._file_finders import find_files
from setuptools_scm._get_version_impl import _get_version
from setuptools_scm._integration.pyproject_reading import PyProjectData
from setuptools_scm.discover import walk_potential_roots


def main(args: list[str] | None = None) -> int:
def main(
args: list[str] | None = None, *, _given_pyproject_data: PyProjectData | None = None
) -> int:
opts = _get_cli_opts(args)
inferred_root: str = opts.root or "."

Expand All @@ -24,6 +27,7 @@ def main(args: list[str] | None = None) -> int:
config = Configuration.from_file(
pyproject,
root=(os.path.abspath(opts.root) if opts.root is not None else None),
pyproject_data=_given_pyproject_data,
)
except (LookupError, FileNotFoundError) as ex:
# no pyproject.toml OR no [tool.setuptools_scm]
Expand Down
26 changes: 23 additions & 3 deletions testing/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .wd_wrapper import WorkDir


def pytest_configure() -> None:
def pytest_configure(config: pytest.Config) -> None:
# 2009-02-13T23:31:30+00:00
os.environ["SOURCE_DATE_EPOCH"] = "1234567890"
os.environ["SETUPTOOLS_SCM_DEBUG"] = "1"
Expand All @@ -42,10 +42,10 @@ def pytest_report_header() -> list[str]:
# Replace everything up to and including site-packages with site::
parts = path.split("site-packages", 1)
if len(parts) > 1:
path = "site:." + parts[1]
path = "site::" + parts[1]
elif path and str(Path.cwd()) in path:
# Replace current working directory with CWD::
path = path.replace(str(Path.cwd()), "CWD:.")
path = path.replace(str(Path.cwd()), "CWD::")
res.append(f"{pkg} version {pkg_version} from {path}")
return res

Expand Down Expand Up @@ -88,8 +88,28 @@ def debug_mode() -> Iterator[DebugMode]:
yield debug_mode


def setup_git_wd(wd: WorkDir, monkeypatch: pytest.MonkeyPatch | None = None) -> WorkDir:
"""Set up a WorkDir with git initialized and configured for testing.

Note: This is a compatibility wrapper. Consider using wd.setup_git() directly.
"""
return wd.setup_git(monkeypatch)


def setup_hg_wd(wd: WorkDir) -> WorkDir:
"""Set up a WorkDir with mercurial initialized and configured for testing.

Note: This is a compatibility wrapper. Consider using wd.setup_hg() directly.
"""
return wd.setup_hg()


@pytest.fixture
def wd(tmp_path: Path) -> WorkDir:
"""Base WorkDir fixture that returns an unconfigured working directory.

Individual test modules should override this fixture to set up specific SCM configurations.
"""
target_wd = tmp_path.resolve() / "wd"
target_wd.mkdir()
return WorkDir(target_wd)
Expand Down
33 changes: 7 additions & 26 deletions testing/test_better_root_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,13 @@
from setuptools_scm._get_version_impl import _version_missing
from testing.wd_wrapper import WorkDir


def setup_git_repo(wd: WorkDir) -> WorkDir:
"""Set up a git repository for testing."""
wd("git init")
wd("git config user.email [email protected]")
wd('git config user.name "a test"')
wd.add_command = "git add ."
wd.commit_command = "git commit -m test-{reason}"
return wd


def setup_hg_repo(wd: WorkDir) -> WorkDir:
"""Set up a mercurial repository for testing."""
try:
wd("hg init")
wd.add_command = "hg add ."
wd.commit_command = 'hg commit -m test-{reason} -u test -d "0 0"'
return wd
except Exception:
pytest.skip("hg not available")
# No longer need to import setup functions - using WorkDir methods directly


def test_find_scm_in_parents_finds_git(wd: WorkDir) -> None:
"""Test that _find_scm_in_parents correctly finds git repositories in parent directories."""
# Set up git repo in root
setup_git_repo(wd)
wd.setup_git()

# Create a subdirectory structure
subdir = wd.cwd / "subproject" / "nested"
Expand All @@ -57,7 +38,7 @@ def test_find_scm_in_parents_finds_git(wd: WorkDir) -> None:
def test_find_scm_in_parents_finds_hg(wd: WorkDir) -> None:
"""Test that _find_scm_in_parents correctly finds mercurial repositories in parent directories."""
# Set up hg repo in root
setup_hg_repo(wd)
wd.setup_hg()

# Create a subdirectory structure
subdir = wd.cwd / "subproject" / "nested"
Expand Down Expand Up @@ -85,7 +66,7 @@ def test_find_scm_in_parents_returns_none(wd: WorkDir) -> None:
def test_version_missing_with_scm_in_parent(wd: WorkDir) -> None:
"""Test that _version_missing provides helpful error message when SCM is found in parent."""
# Set up git repo in root
setup_git_repo(wd)
wd.setup_git()

# Create a subdirectory structure
subdir = wd.cwd / "subproject" / "nested"
Expand Down Expand Up @@ -130,7 +111,7 @@ def test_version_missing_no_scm_found(wd: WorkDir) -> None:
def test_version_missing_with_relative_to_set(wd: WorkDir) -> None:
"""Test that when relative_to is set, we don't search parents for error messages."""
# Set up git repo in root
setup_git_repo(wd)
wd.setup_git()

# Create a subdirectory structure
subdir = wd.cwd / "subproject" / "nested"
Expand Down Expand Up @@ -161,7 +142,7 @@ def test_search_parent_directories_works_as_suggested(
) -> None:
"""Test that the suggested search_parent_directories=True solution actually works."""
# Set up git repo
setup_git_repo(wd)
wd.setup_git()
wd.commit_testfile() # Make sure there's a commit for version detection

# Create a subdirectory
Expand All @@ -182,7 +163,7 @@ def test_integration_better_error_from_nested_directory(
) -> None:
"""Integration test: get_version from nested directory should give helpful error."""
# Set up git repo
setup_git_repo(wd)
wd.setup_git()

# Create a subdirectory
subdir = wd.cwd / "subproject"
Expand Down
105 changes: 75 additions & 30 deletions testing/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,46 @@
import pytest

from setuptools_scm._cli import main
from setuptools_scm._integration.pyproject_reading import PyProjectData

from .conftest import DebugMode
from .test_git import wd as wd_fixture # noqa: F401 (evil fixture reuse)
from .wd_wrapper import WorkDir


@pytest.fixture
def wd(wd: WorkDir, monkeypatch: pytest.MonkeyPatch, debug_mode: DebugMode) -> WorkDir:
"""Set up git for CLI tests."""
debug_mode.disable()
wd.setup_git(monkeypatch)
debug_mode.enable()
return wd


PYPROJECT_TOML = "pyproject.toml"
PYPROJECT_SIMPLE = "[tool.setuptools_scm]"
PYPROJECT_ROOT = '[tool.setuptools_scm]\nroot=".."'

# PyProjectData constants for testing
PYPROJECT_DATA_SIMPLE = PyProjectData.for_testing(section_present=True)
PYPROJECT_DATA_WITH_PROJECT = PyProjectData.for_testing(
section_present=True, project_present=True, project_name="test"
)


def get_output(args: list[str]) -> str:
def _create_version_file_pyproject_data() -> PyProjectData:
"""Create PyProjectData with version_file configuration for testing."""
data = PyProjectData.for_testing(
section_present=True, project_present=True, project_name="test"
)
data.section["version_file"] = "ver.py"
return data


def get_output(
args: list[str], *, _given_pyproject_data: PyProjectData | None = None
) -> str:
with redirect_stdout(io.StringIO()) as out:
main(args)
main(args, _given_pyproject_data=_given_pyproject_data)
return out.getvalue()


Expand Down Expand Up @@ -59,24 +86,20 @@ def test_cli_force_version_files(
) -> None:
debug_mode.disable()
wd.commit_testfile()
wd.write(
PYPROJECT_TOML,
"""
[project]
name = "test"
[tool.setuptools_scm]
version_file = "ver.py"
""",
)
monkeypatch.chdir(wd.cwd)

version_file = wd.cwd.joinpath("ver.py")
assert not version_file.exists()

get_output([])
# Create pyproject data with version_file configuration
pyproject_data = _create_version_file_pyproject_data()

get_output([], _given_pyproject_data=pyproject_data)
assert not version_file.exists()

output = get_output(["--force-write-version-files"])
output = get_output(
["--force-write-version-files"], _given_pyproject_data=pyproject_data
)
assert version_file.exists()

assert output[:5] in version_file.read_text("utf-8")
Expand All @@ -87,13 +110,16 @@ def test_cli_create_archival_file_stable(
) -> None:
"""Test creating stable .git_archival.txt file."""
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

archival_file = wd.cwd / ".git_archival.txt"
assert not archival_file.exists()

result = main(["create-archival-file", "--stable"])
# Use injected pyproject data instead of creating a file
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--stable"], _given_pyproject_data=pyproject_data
)
assert result == 0
assert archival_file.exists()

Expand All @@ -115,13 +141,16 @@ def test_cli_create_archival_file_full(
) -> None:
"""Test creating full .git_archival.txt file with branch information."""
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

archival_file = wd.cwd / ".git_archival.txt"
assert not archival_file.exists()

result = main(["create-archival-file", "--full"])
# Use injected pyproject data instead of creating a file
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--full"], _given_pyproject_data=pyproject_data
)
assert result == 0
assert archival_file.exists()

Expand All @@ -144,15 +173,18 @@ def test_cli_create_archival_file_exists_no_force(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test that existing .git_archival.txt file prevents creation without --force."""
wd.setup_git(monkeypatch)
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

archival_file = wd.cwd / ".git_archival.txt"
archival_file.write_text("existing content", encoding="utf-8")

# Should fail without --force
result = main(["create-archival-file", "--stable"])
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--stable"], _given_pyproject_data=pyproject_data
)
assert result == 1

# Content should be unchanged
Expand All @@ -163,15 +195,19 @@ def test_cli_create_archival_file_exists_with_force(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test that --force overwrites existing .git_archival.txt file."""
wd.setup_git(monkeypatch)
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

archival_file = wd.cwd / ".git_archival.txt"
archival_file.write_text("existing content", encoding="utf-8")

# Should succeed with --force
result = main(["create-archival-file", "--stable", "--force"])
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--stable", "--force"],
_given_pyproject_data=pyproject_data,
)
assert result == 0

# Content should be updated
Expand All @@ -184,41 +220,48 @@ def test_cli_create_archival_file_requires_stable_or_full(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test that create-archival-file requires either --stable or --full."""
wd.setup_git(monkeypatch)
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

# Should fail without --stable or --full
pyproject_data = PYPROJECT_DATA_SIMPLE
with pytest.raises(SystemExit):
main(["create-archival-file"])
main(["create-archival-file"], _given_pyproject_data=pyproject_data)


def test_cli_create_archival_file_mutually_exclusive(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test that --stable and --full are mutually exclusive."""
wd.setup_git(monkeypatch)
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

# Should fail with both --stable and --full
pyproject_data = PYPROJECT_DATA_SIMPLE
with pytest.raises(SystemExit):
main(["create-archival-file", "--stable", "--full"])
main(
["create-archival-file", "--stable", "--full"],
_given_pyproject_data=pyproject_data,
)


def test_cli_create_archival_file_existing_gitattributes(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test behavior when .gitattributes already has export-subst configuration."""
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

# Create .gitattributes with export-subst configuration
gitattributes_file = wd.cwd / ".gitattributes"
gitattributes_file.write_text(".git_archival.txt export-subst\n", encoding="utf-8")

result = main(["create-archival-file", "--stable"])
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--stable"], _given_pyproject_data=pyproject_data
)
assert result == 0

archival_file = wd.cwd / ".git_archival.txt"
Expand All @@ -230,10 +273,12 @@ def test_cli_create_archival_file_no_gitattributes(
) -> None:
"""Test behavior when .gitattributes doesn't exist or lacks export-subst."""
wd.commit_testfile()
wd.write(PYPROJECT_TOML, PYPROJECT_SIMPLE)
monkeypatch.chdir(wd.cwd)

result = main(["create-archival-file", "--stable"])
pyproject_data = PYPROJECT_DATA_SIMPLE
result = main(
["create-archival-file", "--stable"], _given_pyproject_data=pyproject_data
)
assert result == 0

archival_file = wd.cwd / ".git_archival.txt"
Expand Down
Loading
Loading