Skip to content
Merged
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
5 changes: 4 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,14 @@ jobs:
- tests/mock_vws/test_update_target.py::TestWidth
- tests/mock_vws/test_update_target.py::TestInactiveProject
- tests/mock_vws/test_requests_mock_usage.py
- tests/mock_vws/test_respx_mock_usage.py
- tests/mock_vws/test_flask_app_usage.py
- tests/mock_vws/test_vumark_generation_api.py
- tests/mock_vws/test_target_validators.py
- tests/mock_vws/test_docker.py
- ci/test_custom_linters.py
- README.rst
- docs/source/basic-example.rst
- docs/

steps:
- uses: actions/checkout@v6
Expand Down
59 changes: 32 additions & 27 deletions ci/test_custom_linters.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
"""Custom lint tests."""

from pathlib import Path
from typing import TYPE_CHECKING

import pytest
import yaml
from beartype import beartype

if TYPE_CHECKING:
from collections.abc import Iterable


@beartype
def _ci_patterns(*, repository_root: Path) -> set[str]:
Expand All @@ -23,32 +19,44 @@ def _ci_patterns(*, repository_root: Path) -> set[str]:
return ci_patterns


class _CollectPlugin:
"""Pytest plugin that records the node IDs of collected items."""

def __init__(self) -> None:
"""Start with an empty set of collected node IDs."""
self.collected: set[str] = set()

def pytest_itemcollected(self, item: pytest.Item) -> None:
"""Record each collected item's node ID."""
self.collected.add(item.nodeid)


@beartype
def _tests_from_pattern(
*,
ci_pattern: str,
capsys: pytest.CaptureFixture[str],
) -> set[str]:
def _tests_from_pattern(*, ci_pattern: str) -> set[str]:
"""From a CI pattern, get all tests ``pytest`` would collect."""
# Clear the captured output.
capsys.readouterr()
tests: Iterable[str] = set()
plugin = _CollectPlugin()
pytest.main(
args=[
"-q",
"--collect-only",
# If there are any warnings, these obscure the output.
# Disable pytest-retry to avoid:
# ```
# ValueError: no option named 'filtered_exceptions'
# ```
# which causes the nested run to exit with INTERNAL_ERROR
# before any items are collected.
"-p",
"no:pytest-retry",
# Disable warnings to avoid many instances of:
# ```
# Unknown config option: retry_delay
# ```
"--disable-warnings",
ci_pattern,
],
plugins=[plugin],
)
data = capsys.readouterr().out
for line in data.splitlines():
# We filter empty lines and lines which look like
# "9 tests collected in 0.01s".
if line and "collected in" not in line:
tests = {*tests, line}
return set(tests)
return plugin.collected


def test_ci_patterns_valid(request: pytest.FixtureRequest) -> None:
Expand Down Expand Up @@ -82,20 +90,18 @@ def test_ci_patterns_valid(request: pytest.FixtureRequest) -> None:
assert collect_only_result == 0, message


def test_tests_collected_once(
*,
capsys: pytest.CaptureFixture[str],
request: pytest.FixtureRequest,
) -> None:
def test_tests_collected_once(request: pytest.FixtureRequest) -> None:
"""Each test in the test suite is collected exactly once.

This does not necessarily mean that they are run - they may be skipped.
"""
ci_patterns = _ci_patterns(repository_root=request.config.rootpath)
all_tests = _tests_from_pattern(ci_pattern=".")
assert all_tests
tests_to_patterns: dict[str, set[str]] = {}

for pattern in ci_patterns:
tests = _tests_from_pattern(ci_pattern=pattern, capsys=capsys)
tests = _tests_from_pattern(ci_pattern=pattern)
for test in tests:
if test in tests_to_patterns:
tests_to_patterns[test].add(pattern)
Expand All @@ -110,6 +116,5 @@ def test_tests_collected_once(
)
assert len(patterns) == 1, message

all_tests = _tests_from_pattern(ci_pattern=".", capsys=capsys)
assert tests_to_patterns.keys() - all_tests == set()
assert all_tests - tests_to_patterns.keys() == set()
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ ignore_names = [
# pytest configuration
"pytest_collect_file",
"pytest_collection_modifyitems",
"pytest_itemcollected",
"pytest_plugins",
"pytest_set_filtered_exceptions",
"pytest_addoption",
Expand Down
Loading