09e9f3545f
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
dependency-audit / pip-audit (push) Has been cancelled
268 lines
8.6 KiB
Python
268 lines
8.6 KiB
Python
"""Unit tests for test taxonomy inventory helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
|
|
def _load_inventory_script():
|
|
root = Path(__file__).resolve().parents[2]
|
|
path = root / "scripts" / "test_taxonomy_inventory.py"
|
|
spec = importlib.util.spec_from_file_location("test_taxonomy_inventory", path)
|
|
assert spec and spec.loader
|
|
module = importlib.util.module_from_spec(spec)
|
|
# Register before exec so the dataclass machinery can resolve the module by
|
|
# ``cls.__module__`` (Python 3.14's ``dataclasses._is_type`` does a bare
|
|
# ``sys.modules.get(cls.__module__)``). Before the ``tests`` package chain
|
|
# was completed this happened to be satisfied because pytest imported this
|
|
# very test file as the top-level module ``test_taxonomy_inventory``; with
|
|
# fully-qualified ``tests.unit.test_taxonomy_inventory`` it no longer is.
|
|
import sys
|
|
|
|
sys.modules.setdefault(spec.name, module)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def test_logical_module_key_strips_migration_suffixes() -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
assert (
|
|
inventory.logical_module_key("tests/integration/test_sources_integration.py") == "sources"
|
|
)
|
|
assert inventory.logical_module_key("tests/unit/test_source_characterization.py") == "source"
|
|
assert inventory.logical_module_key("tests/unit/test_artifacts_vcr.py") == "artifacts"
|
|
assert inventory.logical_module_key("tests/unit/test_notes_mock.py") == "notes"
|
|
|
|
|
|
def test_normalized_identity_preserves_class_function_and_parameter_id() -> None:
|
|
inventory = _load_inventory_script()
|
|
record = inventory.ItemRecord(
|
|
nodeid=(
|
|
"tests/integration/test_sources_integration.py::"
|
|
"TestSourcesAPI::test_list_sources[case-a]"
|
|
),
|
|
path="tests/integration/test_sources_integration.py",
|
|
markers=frozenset(),
|
|
)
|
|
|
|
assert (
|
|
inventory.normalized_identity(record)
|
|
== "sources::TestSourcesAPI::test_list_sources[case-a]"
|
|
)
|
|
|
|
|
|
def test_normalized_identity_uses_nodeid_delimiter_for_suffix() -> None:
|
|
inventory = _load_inventory_script()
|
|
record = inventory.ItemRecord(
|
|
nodeid=(
|
|
"C:\\work\\repo\\tests\\integration\\test_sources_integration.py::"
|
|
"TestSourcesAPI::test_list_sources"
|
|
),
|
|
path="tests/integration/test_sources_integration.py",
|
|
markers=frozenset(),
|
|
)
|
|
|
|
assert inventory.normalized_identity(record) == "sources::TestSourcesAPI::test_list_sources"
|
|
|
|
|
|
def test_duplicate_normalized_identities_are_reported() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/integration/test_sources_integration.py::test_same",
|
|
path="tests/integration/test_sources_integration.py",
|
|
markers=frozenset(),
|
|
),
|
|
inventory.ItemRecord(
|
|
nodeid="tests/unit/test_sources.py::test_same",
|
|
path="tests/unit/test_sources.py",
|
|
markers=frozenset(),
|
|
),
|
|
]
|
|
|
|
duplicates = inventory.duplicate_normalized_identities(records)
|
|
|
|
assert duplicates == {
|
|
"sources::test_same": [
|
|
"tests/integration/test_sources_integration.py::test_same",
|
|
"tests/unit/test_sources.py::test_same",
|
|
]
|
|
}
|
|
|
|
|
|
def test_move_map_disambiguates_duplicate_normalized_identities() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/integration/test_sources_integration.py::test_same",
|
|
path="tests/integration/test_sources_integration.py",
|
|
markers=frozenset(),
|
|
),
|
|
inventory.ItemRecord(
|
|
nodeid="tests/unit/test_sources.py::test_same",
|
|
path="tests/unit/test_sources.py",
|
|
markers=frozenset(),
|
|
),
|
|
]
|
|
|
|
duplicates = inventory.duplicate_normalized_identities(
|
|
records,
|
|
move_map={"tests/unit/test_sources.py::test_same": "sources_unit::test_same"},
|
|
)
|
|
|
|
assert duplicates == {}
|
|
|
|
|
|
def test_collect_items_uses_repo_absolute_tests_path(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
inventory = _load_inventory_script()
|
|
captured: dict[str, Any] = {}
|
|
|
|
def fake_pytest_main(args, plugins):
|
|
captured["args"] = args
|
|
captured["plugins"] = plugins
|
|
return 0
|
|
|
|
monkeypatch.setattr(inventory.pytest, "main", fake_pytest_main)
|
|
|
|
assert inventory.collect_items() == []
|
|
assert captured["args"][-1] == str(inventory.TESTS_DIR)
|
|
assert Path(captured["args"][-1]).is_absolute()
|
|
|
|
|
|
def test_allowlist_entries_from_text_ignores_comments_and_rationales() -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
entries = inventory.allowlist_entries_from_text(
|
|
"\n"
|
|
"# comment\n"
|
|
"tests/integration/test_a.py # reviewed reason\n"
|
|
"tests/integration/test_b.py #reviewed reason without spacing\n"
|
|
"tests/integration/test_c.py # reviewed reason with extra spacing\n"
|
|
"tests/integration/test_hash#name.py # reviewed reason\n"
|
|
)
|
|
|
|
assert entries == [
|
|
"tests/integration/test_a.py",
|
|
"tests/integration/test_b.py",
|
|
"tests/integration/test_c.py",
|
|
"tests/integration/test_hash#name.py",
|
|
]
|
|
|
|
|
|
def test_taxonomy_policy_is_file_level_not_nodeid_level() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/integration/test_mock.py::test_renamed",
|
|
path="tests/integration/test_mock.py",
|
|
markers=frozenset({"allow_no_vcr"}),
|
|
),
|
|
inventory.ItemRecord(
|
|
nodeid="tests/e2e/test_live.py::test_live",
|
|
path="tests/e2e/test_live.py",
|
|
markers=frozenset({"e2e"}),
|
|
),
|
|
]
|
|
|
|
violations = inventory.taxonomy_policy_violations(
|
|
records,
|
|
allow_no_vcr_files=["tests/integration/test_mock.py"],
|
|
)
|
|
|
|
assert violations == []
|
|
|
|
|
|
def test_taxonomy_policy_flags_new_allow_no_vcr_files() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/integration/test_new_mock.py::test_mock_only",
|
|
path="tests/integration/test_new_mock.py",
|
|
markers=frozenset({"allow_no_vcr"}),
|
|
),
|
|
]
|
|
|
|
violations = inventory.taxonomy_policy_violations(records, allow_no_vcr_files=[])
|
|
|
|
assert len(violations) == 1
|
|
assert "tests/integration/test_new_mock.py" in violations[0]
|
|
|
|
|
|
def test_taxonomy_policy_flags_e2e_items_without_marker() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/e2e/test_live.py::test_live",
|
|
path="tests/e2e/test_live.py",
|
|
markers=frozenset(),
|
|
),
|
|
]
|
|
|
|
violations = inventory.taxonomy_policy_violations(records, allow_no_vcr_files=[])
|
|
|
|
assert len(violations) == 1
|
|
assert "tests/e2e/test_live.py::test_live" in violations[0]
|
|
|
|
|
|
def test_taxonomy_policy_flags_cassette_without_vcr_marker() -> None:
|
|
inventory = _load_inventory_script()
|
|
records = [
|
|
inventory.ItemRecord(
|
|
nodeid="tests/integration/test_live.py::test_live",
|
|
path="tests/integration/test_live.py",
|
|
markers=frozenset(),
|
|
has_use_cassette=True,
|
|
),
|
|
]
|
|
|
|
violations = inventory.taxonomy_policy_violations(records, allow_no_vcr_files=[])
|
|
|
|
assert len(violations) == 1
|
|
assert "tests/integration/test_live.py::test_live" in violations[0]
|
|
|
|
|
|
def test_taxonomy_policy_flags_stale_allow_no_vcr_files() -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
violations = inventory.taxonomy_policy_violations(
|
|
[],
|
|
allow_no_vcr_files=["tests/integration/test_old_mock.py"],
|
|
)
|
|
|
|
assert len(violations) == 1
|
|
assert "tests/integration/test_old_mock.py" in violations[0]
|
|
|
|
|
|
def test_rendered_baseline_outputs_excludes_audit_report() -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
outputs = inventory.rendered_baseline_outputs([])
|
|
|
|
assert inventory.DEFAULT_REPORT_PATH not in outputs
|
|
assert set(outputs) == {
|
|
inventory.ALLOW_NO_VCR_FILES_PATH,
|
|
inventory.ALLOW_NO_VCR_NODEIDS_PATH,
|
|
inventory.VCR_ALLOW_NO_VCR_NODEIDS_PATH,
|
|
}
|
|
|
|
|
|
def test_main_rejects_conflicting_actions() -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
with pytest.raises(SystemExit):
|
|
inventory.main(["--check", "--write-report"])
|
|
|
|
|
|
def test_main_rejects_report_path_without_write_report(tmp_path: Path) -> None:
|
|
inventory = _load_inventory_script()
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
inventory.main(["--report-path", str(tmp_path / "taxonomy.md")])
|
|
|
|
assert exc_info.value.code == 2
|