# 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()