_host_matches_platforms turned a misspelt spec (platforms("linx")) into
a skip, so the test vanished on every host with both lanes green — the
exact silent-drop class the collection guard exists to catch. Validate
every spec first and raise pytest.UsageError naming the item; a matching
sibling spec no longer excuses a typo next to it.
55 lines
2.6 KiB
Python
55 lines
2.6 KiB
Python
"""Run the real collection hook; skip-all and unregistered guards must fail."""
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
|
|
_INVALID_MARKERS = {
|
|
"stacked": "@pytest.mark.platforms('any')",
|
|
"keyword": "@pytest.mark.platforms('any', bogus=True)",
|
|
"typo": "@pytest.mark.platforms('linx')",
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize("invalid,message", [("", ""), ("stacked", "at most one platforms()"),
|
|
("keyword", "unexpected keyword"),
|
|
("typo", "unknown spec")])
|
|
def test_native_collection_witnesses(tmp_path, invalid, message):
|
|
root = Path(__file__).resolve().parents[1]
|
|
host = {"linux": "linux", "darwin": "macos", "win32": "windows"}[sys.platform]
|
|
(tmp_path / "conftest.py").write_text(
|
|
f"import sys; sys.path.insert(0, {str(root)!r})\n"
|
|
"from tests.conftest import pytest_configure, pytest_collection_modifyitems\n", encoding="utf-8")
|
|
suite = "import pytest\nfrom pathlib import Path\n"
|
|
for name, marker in [
|
|
("plain", ""), ("any", "@pytest.mark.platforms('any')"),
|
|
("native", f"@pytest.mark.platforms({host!r})"),
|
|
("foreign", f"@pytest.mark.platforms('not {host}')"),
|
|
("arch", "@pytest.mark.platforms('any', arch='nonexistent-architecture')"),
|
|
]:
|
|
suite += f"{marker}\ndef test_{name}():\n Path({name!r}).touch()\n"
|
|
(tmp_path / "test_valid.py").write_text(suite, encoding="utf-8")
|
|
if invalid:
|
|
marker = _INVALID_MARKERS[invalid]
|
|
module_mark = "pytestmark = pytest.mark.platforms('any')\n" if invalid == "stacked" else ""
|
|
(tmp_path / "test_bad.py").write_text(
|
|
f"import pytest\n{module_mark}{marker}\ndef test_bad():\n raise AssertionError('must reject collection')\n",
|
|
encoding="utf-8")
|
|
result = subprocess.run([sys.executable, "-m", "pytest", "-q", "-o", "addopts=", str(tmp_path)],
|
|
cwd=tmp_path, env={**os.environ, "PYTEST_DISABLE_PLUGIN_AUTOLOAD": "1"},
|
|
capture_output=True, text=True, timeout=30)
|
|
output = result.stdout + result.stderr
|
|
witnesses = {p.name for p in tmp_path.iterdir() if p.name in {"plain", "any", "native", "foreign", "arch"}}
|
|
if invalid:
|
|
assert result.returncode == 4, output
|
|
assert message in output and "test_bad.py::test_bad" in output
|
|
assert "test_valid.py::" not in output
|
|
assert not witnesses
|
|
else:
|
|
assert result.returncode == 0, output
|
|
assert "3 passed, 2 skipped" in output
|
|
assert witnesses == {"plain", "any", "native"}
|