Files
pgr/tests/test_rust_export_completeness.py
2026-09-25 00:36:24 +02:00

133 lines
5.3 KiB
Python

# file: tests/test_rust_export_completeness.py
# version: 1
"""Regression tests for the optional Rust crate-root façade audit."""
from __future__ import annotations
import pathlib
import subprocess
import sys
import tempfile
import unittest
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "scripts"))
from audit_rust_export_completeness import audit_workspace # noqa: E402
class RustExportCompletenessTests(unittest.TestCase):
def setUp(self) -> None:
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
self.root = pathlib.Path(self.temporary.name)
def crate(self, relative: str, root_source: str, files: dict[str, str]) -> pathlib.Path:
crate = self.root / relative
(crate / "src").mkdir(parents=True)
(crate / "Cargo.toml").write_text(
'[package]\nname = "fixture"\nversion = "0.1.0"\nedition = "2024"\n',
encoding="utf-8",
)
(crate / "src/lib.rs").write_text(root_source, encoding="utf-8")
for name, text in files.items():
path = crate / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding="utf-8")
return crate
def candidates(self) -> list[object]:
_, candidates = audit_workspace(self.root)
return candidates
def test_nested_crate_layout_is_discovered(self) -> None:
self.crate("crates/common/example-lib", "mod api;\npub use self::api::Thing;\n", {"src/api.rs": "pub struct Thing;\n"})
crates, candidates = audit_workspace(self.root)
self.assertEqual(len(crates), 1)
self.assertEqual(candidates, [])
def test_missing_public_reexport_is_rejected(self) -> None:
self.crate("crates/example-lib", "mod api;\n", {"src/api.rs": "pub struct Thing;\n"})
candidates = self.candidates()
self.assertEqual([candidate.code for candidate in candidates], ["RUST-API-201"])
def test_external_crate_public_item_requires_reexport(self) -> None:
self.crate(
"crates/example-lib",
"mod api;\nmod consumer;\n",
{
"src/api.rs": "pub(crate) const VALUE: u8 = 1;\n",
"src/consumer.rs": "pub(crate) fn value() -> u8 { return crate::api::VALUE; }\n",
},
)
self.assertTrue(any(candidate.code == "RUST-API-201" for candidate in self.candidates()))
def test_unused_crate_public_item_does_not_force_reexport(self) -> None:
self.crate("crates/example-lib", "mod api;\n", {"src/api.rs": "pub(crate) const VALUE: u8 = 1;\n"})
self.assertEqual(self.candidates(), [])
def test_exported_item_requires_crate_root_path(self) -> None:
self.crate(
"crates/example-lib",
"mod api;\nmod consumer;\npub use self::api::Thing;\n",
{
"src/api.rs": "pub struct Thing;\n",
"src/consumer.rs": "pub(crate) fn make() -> crate::api::Thing { return crate::api::Thing; }\n",
},
)
candidates = self.candidates()
self.assertTrue(any(candidate.code == "RUST-IMPORT-201" for candidate in candidates))
def test_grouped_and_aliased_reexports_are_understood(self) -> None:
self.crate(
"crates/example-lib",
"mod api;\npub use self::api::{First, Second as PublicSecond};\n",
{"src/api.rs": "pub struct First;\npub struct Second;\n"},
)
self.assertEqual(self.candidates(), [])
def test_mod_rs_maps_to_parent_module(self) -> None:
self.crate(
"crates/example-lib",
"mod api;\npub use self::api::Thing;\n",
{"src/api/mod.rs": "pub struct Thing;\n"},
)
self.assertEqual(self.candidates(), [])
def test_comments_and_literals_do_not_create_long_path_candidates(self) -> None:
self.crate(
"crates/example-lib",
"mod api;\nmod consumer;\npub use self::api::Thing;\n",
{
"src/api.rs": "pub struct Thing;\n",
"src/consumer.rs": 'pub(crate) fn text() -> &\'static str { return "crate::api::Thing"; } // crate::api::Thing\n',
},
)
self.assertEqual(self.candidates(), [])
def test_cli_status_for_clean_violation_report_only_and_missing_crates(self) -> None:
script = pathlib.Path(__file__).resolve().parents[1] / "scripts" / "audit_rust_export_completeness.py"
def run(root: pathlib.Path, *extra: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, "-B", str(script), "--root", str(root), *extra],
capture_output=True,
text=True,
check=False,
)
empty = self.root / "empty"
empty.mkdir()
self.assertEqual(run(empty).returncode, 2)
self.crate("crates/example-lib", "mod api;\npub use self::api::Thing;\n", {"src/api.rs": "pub struct Thing;\n"})
self.assertEqual(run(self.root).returncode, 0)
(self.root / "crates/example-lib/src/lib.rs").write_text("mod api;\n", encoding="utf-8")
self.assertEqual(run(self.root).returncode, 1)
self.assertEqual(run(self.root, "--report-only").returncode, 0)
if __name__ == "__main__":
unittest.main()