use super::super::*;
use super::helpers::*;
pub(super) fn locality_findings(
name: &str,
files: &[(&str, &str)],
trait_path: &str,
allowed: &[&str],
) -> Result<Vec<String>, String> {
let tree = TempSrcTree::new(&format!("loc-{name}"));
tree.write_all(files);
let allowed: Vec<String> = allowed.iter().map(|s| s.to_string()).collect();
let result = trait_impl_findings(tree.src(), &tree.root(), trait_path, &allowed, "x");
result.map(|reaction| {
reaction
.findings
.into_iter()
.map(|(finding, _module, _file)| finding.to_string())
.collect()
})
}
pub(super) fn locality_anchor(
name: &str,
files: &[(&str, &str)],
trait_path: &str,
) -> Result<String, String> {
let tree = TempSrcTree::new(&format!("loc-anchor-{name}"));
tree.write_all(files);
trait_impl_findings(tree.src(), &tree.root(), trait_path, &[], "x").map(|r| r.anchor)
}
#[test]
pub(super) fn trait_impl_anchor_reacts_when_the_forbidden_alias_is_declared_first() {
let out = locality_findings(
"anchor-cfg-forbidden-first",
&[
("lib.rs", "pub mod command;\npub mod other;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
("other.rs", "pub trait Other {}\n"),
(
"domain.rs",
"#[cfg(unix)]\nuse crate::command::Command as T;\n#[cfg(not(unix))]\nuse crate::other::Other as T;\npub struct Foo;\nimpl T for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn trait_impl_anchor_reacts_when_the_forbidden_alias_is_declared_second() {
let out = locality_findings(
"anchor-cfg-forbidden-second",
&[
("lib.rs", "pub mod command;\npub mod other;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
("other.rs", "pub trait Other {}\n"),
(
"domain.rs",
"#[cfg(not(unix))]\nuse crate::other::Other as T;\n#[cfg(unix)]\nuse crate::command::Command as T;\npub struct Foo;\nimpl T for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn an_impl_outside_the_allowed_location_is_a_finding() {
let out = locality_findings(
"outside",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn two_misplaced_impls_do_not_dedup_collapse_when_a_blanket_impls_param_shadows_an_alias()
{
let out = locality_findings(
"owner-collapse-blanket-and-direct",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\nuse crate::domain::sub::Foo as T;\npub mod sub { pub struct Foo; }\nimpl<T> Command for T {}\nimpl Command for crate::domain::sub::Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out.len(),
2,
"both the blanket impl (its own param T) and the direct impl on Foo are genuinely distinct \
misplaced-impl violations and must not dedup-collapse into one: {out:?}"
);
}
#[test]
pub(super) fn a_cfg_dual_declared_module_backed_by_one_file_does_not_duplicate_its_impl_finding() {
let out = locality_findings(
"cfg-dual-same-file",
&[
(
"lib.rs",
"pub trait Command {}\npub struct Arr<const N: usize>;\n\
#[cfg(feature = \"u\")]\npub mod foo;\n#[cfg(feature = \"w\")]\npub mod foo;\n",
),
("foo.rs", "impl crate::Command for crate::Arr<2> {}\n"),
],
"crate::Command",
&["crate::allowed_elsewhere"],
)
.unwrap();
assert_eq!(
out.len(),
1,
"one real impl, backed by one real file under either #[cfg] arm, must be one finding: {out:?}"
);
}
#[test]
pub(super) fn an_impl_inside_the_allowed_location_is_clean() {
let out = locality_findings(
"inside",
&[
("lib.rs", "pub mod command;\npub mod commands;\n"),
("command.rs", "pub trait Command {}\n"),
(
"commands.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
out.is_empty(),
"an impl in the allowed location is clean: {out:?}"
);
}
#[test]
pub(super) fn a_nested_module_beneath_the_allowed_prefix_is_clean() {
let out = locality_findings(
"nested-allowed",
&[
("lib.rs", "pub mod command;\npub mod commands;\n"),
("command.rs", "pub trait Command {}\n"),
("commands.rs", "pub mod greet;\n"),
(
"commands/greet.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
out.is_empty(),
"beneath an allowed prefix is clean: {out:?}"
);
}
#[test]
pub(super) fn a_prefix_colliding_sibling_location_is_not_allowed() {
let out = locality_findings(
"sibling",
&[
("lib.rs", "pub mod command;\npub mod commandeer;\n"),
("command.rs", "pub trait Command {}\n"),
(
"commandeer.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::commandeer (impl crate::command::Command for crate::commandeer::Foo)"],
"a sibling of the allowed prefix is not allowed"
);
}
#[test]
pub(super) fn an_impl_in_any_of_several_allowed_locations_is_clean() {
let out = locality_findings(
"multi-allowed",
&[
("lib.rs", "pub mod command;\npub mod builtins;\n"),
("command.rs", "pub trait Command {}\n"),
(
"builtins.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands", "crate::builtins"],
)
.unwrap();
assert!(out.is_empty(), "any one allowed location suffices: {out:?}");
}
#[test]
pub(super) fn a_bare_same_module_trait_name_reacts() {
let out = locality_findings(
"bare-same-module",
&[
("lib.rs", "pub mod command;\n"),
(
"command.rs",
"pub trait Command {}\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::command (impl crate::command::Command for crate::command::Foo)"]
);
}
#[test]
pub(super) fn a_renamed_trait_import_reacts() {
let out = locality_findings(
"renamed-trait",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command as Cmd;\npub struct Foo;\nimpl Cmd for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn a_super_relative_trait_import_reacts() {
let out = locality_findings(
"super-trait",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use super::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn a_cfg_gated_module_with_no_file_is_skipped_not_errored() {
let out = locality_findings(
"cfg-absent-mod",
&[
(
"lib.rs",
"pub mod command;\n#[cfg(feature = \"never\")]\npub mod optional;\n",
),
("command.rs", "pub trait Command {}\n"),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
out.is_empty(),
"a cfg-gated absent module is skipped: {out:?}"
);
}
#[test]
pub(super) fn a_reexported_trait_path_reacts() {
let out = locality_findings(
"reexport-impl",
&[
(
"lib.rs",
"pub mod command;\npub mod facade;\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
("facade.rs", "pub use crate::command::Command;\n"),
(
"domain.rs",
"use crate::facade::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn an_anchor_named_at_a_reexport_path_resolves_not_a_constitution_error() {
let out = locality_findings(
"reexport-anchor",
&[
(
"lib.rs",
"pub mod command;\npub mod facade;\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
("facade.rs", "pub use crate::command::Command;\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::facade::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn an_unresolvable_trait_anchor_is_a_constitution_error() {
let err = locality_findings(
"ghost-trait",
&[
("lib.rs", "pub mod command;\n"),
("command.rs", "pub trait Command {}\n"),
],
"crate::command::Ghost",
&["crate::commands"],
)
.unwrap_err();
assert_eq!(err, unknown_trait_error("crate::command::Ghost", "x"));
}
#[test]
pub(super) fn trait_impl_rejects_a_malformed_colon_allowed_location() {
let files: &[(&str, &str)] = &[
("lib.rs", "pub mod api;\n"),
(
"api.rs",
"pub trait Command {}\npub struct Foo;\nimpl Command for Foo {}\n",
),
];
for bad in ["::crate::api", "crate::api::", "crate::api::::sub"] {
let err = locality_findings("malformed-allowed", files, "crate::api::Command", &[bad])
.unwrap_err();
assert!(
err.contains(bad),
"constitution error must name the malformed allowed entry {bad:?}: {err}"
);
}
let empty_err = locality_findings(
"malformed-allowed-empty",
files,
"crate::api::Command",
&[""],
)
.unwrap_err();
assert!(
empty_err.contains("is empty"),
"constitution error must flag the empty allowed entry: {empty_err}"
);
let clean = locality_findings(
"malformed-allowed-control",
files,
"crate::api::Command",
&["crate::api"],
)
.unwrap();
assert!(
clean.is_empty(),
"a well-formed allowed entry must still admit the in-place impl: {clean:?}"
);
}
#[test]
pub(super) fn a_non_anchored_traits_impl_is_ignored() {
let out = locality_findings(
"other-trait",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\npub trait Other {}\n"),
(
"domain.rs",
"use crate::command::Other;\npub struct Foo;\nimpl Other for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(out.is_empty(), "only the anchored trait reacts: {out:?}");
}
#[test]
pub(super) fn an_inline_module_impl_is_located() {
let out = locality_findings(
"inline-impl",
&[
(
"lib.rs",
"pub mod command;\npub mod domain { use crate::command::Command; pub struct Foo; impl Command for Foo {} }\n",
),
("command.rs", "pub trait Command {}\n"),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn a_glob_imported_trait_is_a_documented_bound() {
let out = locality_findings(
"glob-trait",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::*;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
out.is_empty(),
"a glob-imported trait is out of scope, not silently matched: {out:?}"
);
}
#[test]
pub(super) fn an_unconditional_path_remapped_module_is_followed_and_its_impl_reacts() {
let out = locality_findings(
"path-remapped",
&[
(
"lib.rs",
"pub mod command;\n#[path = \"weird.rs\"]\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
(
"weird.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"],
"the impl in the #[path]-relocated module is followed and reacts: {out:?}"
);
}
#[test]
pub(super) fn a_cfg_attr_remapped_module_target_is_followed_when_the_conventional_file_is_absent() {
let out = locality_findings(
"cfg-attr-remapped",
&[
(
"lib.rs",
"pub mod command;\n#[cfg_attr(windows, path = \"weird.rs\")]\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
(
"weird.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"],
"the impl in the cfg_attr-remapped module is followed and reacts: {out:?}"
);
let nested = locality_findings(
"cfg-attr-nested-remapped",
&[
(
"lib.rs",
"pub mod command;\n#[cfg_attr(a, cfg_attr(b, path = \"weird.rs\"))]\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
(
"weird.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
nested,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"],
"the impl in the nested-cfg_attr-remapped module is followed and reacts: {nested:?}"
);
}
#[test]
pub(super) fn a_cfg_attr_without_a_path_meta_is_scanned_normally() {
let out = locality_findings(
"cfg-attr-no-path",
&[
(
"lib.rs",
"pub mod command;\n#[cfg_attr(test, allow(dead_code))]\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
!out.is_empty(),
"a cfg_attr without a path meta is a normal module and must be scanned: {out:?}"
);
let bare = locality_findings(
"cfg-attr-bare-path",
&[
(
"lib.rs",
"pub mod command;\n#[cfg_attr(test, path)]\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct Foo;\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
!bare.is_empty(),
"a bare `path` meta (not `path = \"…\"`) is not a remap; the module is scanned: {bare:?}"
);
}
#[test]
pub(super) fn two_impls_in_one_module_are_distinct_findings_by_self_type() {
let out = locality_findings(
"distinct-self",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct A;\npub struct B;\nimpl Command for A {}\nimpl Command for B {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
[
"crate::domain (impl crate::command::Command for crate::domain::A)",
"crate::domain (impl crate::command::Command for crate::domain::B)"
]
);
}
#[test]
pub(super) fn two_equivalent_trait_spellings_resolve_to_one_anchor_identity() {
let files: &[(&str, &str)] = &[
(
"lib.rs",
"pub mod command;\npub mod api;\npub mod domain;\n",
),
("command.rs", "pub trait Command {}\n"),
("api.rs", "pub use crate::command::Command;\n"),
(
"domain.rs",
"pub struct Foo;\nimpl crate::command::Command for Foo {}\n",
),
];
let (metadata, _tree) = fixture_metadata("spelling-identity", files);
let ids_for = |declared: &str| {
let boundary = TraitImplBoundary::in_crate("x")
.trait_("crate::command::Command")
.only_implemented_in("crate::command")
.because("locality");
let boundary = TraitImplBoundary {
trait_path: declared.to_string(),
..boundary
};
let mut violations = Vec::new();
check_trait_impl_boundary(&metadata, &boundary, &mut violations).unwrap();
violations.iter().map(|v| v.id()).collect::<Vec<_>>()
};
let via_facade = ids_for("crate::api::Command");
let via_defining = ids_for("crate::command::Command");
assert_eq!(via_facade.len(), 1, "the fixture must really violate");
assert_eq!(
via_facade, via_defining,
"two equivalent spellings of one trait must publish one violation identity, or a pure \
declaration refactor invalidates every baseline entry for the same real fact"
);
assert_eq!(
locality_anchor("facade", files, "crate::api::Command").unwrap(),
"crate::command::Command",
"and the anchor itself is the defining path, not the facade as declared"
);
}
#[test]
pub(super) fn a_cfg_collided_trait_facade_is_a_constitution_error() {
let error = locality_anchor(
"collided-facade",
&[
(
"lib.rs",
"pub mod a;\npub mod b;\npub mod api;\npub mod domain;\n",
),
("a.rs", "pub trait Command {}\n"),
("b.rs", "pub trait Command {}\n"),
(
"api.rs",
"#[cfg(unix)]\npub use crate::a::Command;\n#[cfg(not(unix))]\npub use crate::b::Command;\n",
),
("domain.rs", "pub struct Foo;\n"),
],
"crate::api::Command",
)
.unwrap_err();
for expected in [
"must anchor to exactly one trait",
"crate::a::Command",
"crate::b::Command",
"Declare the defining path instead of the facade",
] {
assert!(
error.contains(expected),
"the error must name the ambiguity and both candidates, missing `{expected}`: {error}"
);
}
}
#[test]
pub(super) fn a_cfg_collided_self_type_alias_fails_loud_instead_of_collapsing_two_owners() {
let error = locality_findings(
"cfg-collided-owner-alias",
&[
(
"lib.rs",
"pub mod marker;\npub mod a;\npub mod b;\npub mod domain;\n",
),
("marker.rs", "pub trait Marker {}\n"),
("a.rs", "pub struct Foo;\n"),
("b.rs", "pub struct Bar;\n"),
(
"domain.rs",
"#[cfg(unix)]\nuse crate::a::Foo as X;\n#[cfg(not(unix))]\nuse crate::b::Bar as X;\n\
impl crate::marker::Marker for X {}\n",
),
],
"crate::marker::Marker",
&["crate::marker"],
)
.unwrap_err();
assert!(
error.contains("without a stable structural label"),
"the ambiguity must reach the shared fail-loud identity gate: {error}"
);
assert!(
error.contains("mutually-exclusive"),
"the diagnostic must name the cfg collision as the cause, not just the failure: {error}"
);
assert!(
!error.contains("_#"),
"the internal sentinel must never surface to an adopter: {error}"
);
}
#[test]
pub(super) fn a_single_aliased_self_type_still_resolves_to_its_owner() {
let out = locality_findings(
"single-alias-owner",
&[
("lib.rs", "pub mod marker;\npub mod a;\npub mod domain;\n"),
("marker.rs", "pub trait Marker {}\n"),
("a.rs", "pub struct Foo;\n"),
(
"domain.rs",
"use crate::a::Foo as X;\nimpl crate::marker::Marker for X {}\n",
),
],
"crate::marker::Marker",
&["crate::marker"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::marker::Marker for crate::a::Foo)"],
"a single alias candidate must still render its resolved owner"
);
}
#[test]
pub(super) fn const_generic_expr_self_types_fail_loud_without_positional_identity() {
let error = findings(
"const-generic-expr",
&[
("lib.rs", "pub mod domain;\n"),
(
"domain.rs",
"pub struct Arr<const N: usize>(u8);\n\
impl Arr<{ 1 + 1 }> { pub fn a(&self) -> crate::infra::T { todo!() } }\n\
impl Arr<{ 2 + 2 }> { pub fn a(&self) -> crate::infra::T { todo!() } }\n",
),
],
"crate::domain",
&["crate::infra"],
)
.unwrap_err();
assert!(error.contains("stable structural label"), "{error}");
assert!(!error.contains("_#"), "{error}");
}
#[test]
pub(super) fn owner_is_canonical_across_written_forms() {
let out = findings(
"canonical-forms",
&[
("lib.rs", "pub mod m;\n"),
(
"m.rs",
"pub struct Foo;\n\
impl Foo { pub fn a(&self) -> crate::infra::T { todo!() } }\n\
impl crate::m::Foo { pub fn b(&self) -> crate::infra::T { todo!() } }\n",
),
],
"crate::m",
&["crate::infra"],
)
.unwrap();
assert_eq!(
out,
[
"crate::infra::T exposed by fn <crate::m::Foo>::a",
"crate::infra::T exposed by fn <crate::m::Foo>::b",
],
"both written forms of the same self type render the identical canonical owner",
);
}
#[test]
pub(super) fn a_cfg_gated_impl_is_observed_as_written() {
let out = locality_findings(
"cfg-gated",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
(
"domain.rs",
"use crate::command::Command;\npub struct Foo;\n#[cfg(feature = \"never\")]\nimpl Command for Foo {}\n",
),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert_eq!(
out,
["crate::domain (impl crate::command::Command for crate::domain::Foo)"]
);
}
#[test]
pub(super) fn a_macro_generated_impl_is_a_documented_bound() {
let out = locality_findings(
"macro-impl",
&[
("lib.rs", "pub mod command;\npub mod domain;\n"),
("command.rs", "pub trait Command {}\n"),
("domain.rs", "make_impl!(Foo);\n"),
],
"crate::command::Command",
&["crate::commands"],
)
.unwrap();
assert!(
out.is_empty(),
"a macro-generated impl is out of scope, not silently matched: {out:?}"
);
}
#[test]
pub(super) fn the_builder_carries_severity() {
let warn = TraitImplBoundary::in_crate("app")
.trait_("crate::command::Command")
.only_implemented_in("crate::commands")
.warn()
.because("advisory first");
assert_eq!(warn.severity(), Severity::Warn);
let enforce = TraitImplBoundary::in_crate("app")
.trait_("crate::command::Command")
.only_implemented_in("crate::commands")
.because("enforced");
assert_eq!(enforce.severity(), Severity::Enforce);
}
#[test]
pub(super) fn every_hunyi_rule_family_has_exact_semantic_identity() {
fn assert_rule(rule: xuanji::RuleKey, expected_type: &str, expected_fields: &[(&str, &str)]) {
assert_eq!(rule.rule_type(), expected_type);
assert_eq!(rule.fields().collect::<Vec<_>>(), expected_fields);
}
let signature = SignatureBoundary::in_crate("x")
.module("crate::api")
.must_not_expose("r#crate::infra")
.and_not_expose("crate::storage")
.including_trait_impls()
.because("presentation only");
assert_rule(
signature.rule_key(),
"tianheng.rule/hunyi/signature-exposure",
&[
("forbidden", "[\"crate::infra\",\"crate::storage\"]"),
("including_trait_impls", "true"),
],
);
let dyn_trait = DynTraitBoundary::in_crate("x")
.module("crate::api")
.must_not_expose_dyn_of(["crate::Port", "crate::Other"])
.because("r");
assert_rule(
dyn_trait.rule_key(),
"tianheng.rule/hunyi/dyn-trait-exposure",
&[("forbidden_operands", "[\"crate::Other\",\"crate::Port\"]")],
);
let impl_trait = ImplTraitBoundary::in_crate("x")
.module("crate::api")
.must_not_expose_impl_trait_of(["crate::Port"])
.including_submodules()
.because("r");
assert_rule(
impl_trait.rule_key(),
"tianheng.rule/hunyi/impl-trait-exposure",
&[("forbidden_operands", "[\"crate::Port\"]")],
);
let locality = TraitImplBoundary::in_crate("x")
.trait_("r#crate::Port")
.only_implemented_in("crate::adapter")
.and_in("crate::infra")
.because("r");
assert_rule(
locality.rule_key(),
"tianheng.rule/hunyi/trait-impl-locality",
&[
("allowed_locations", "[\"crate::adapter\",\"crate::infra\"]"),
("trait", "crate::Port"),
],
);
let marker = ForbiddenMarkerBoundary::in_crate("x")
.module("crate::domain")
.must_not_acquire("serde::Serialize")
.and_not_acquire("serde::Deserialize")
.because("r");
assert_rule(
marker.rule_key(),
"tianheng.rule/hunyi/forbidden-marker",
&[("forbidden", "[\"serde::Deserialize\",\"serde::Serialize\"]")],
);
let visibility = VisibilityBoundary::in_crate("x")
.module("crate::internal")
.max_visibility(VisibilityCeiling::Super)
.because("r");
assert_rule(
visibility.rule_key(),
"tianheng.rule/hunyi/visibility-ceiling",
&[("ceiling", "super")],
);
let async_exposure = AsyncExposureBoundary::in_crate("x")
.module("crate::core")
.must_not_expose_async_fn()
.including_submodules()
.because("r");
assert_rule(
async_exposure.rule_key(),
"tianheng.rule/hunyi/async-exposure",
&[],
);
let unsafe_confinement = UnsafeBoundary::in_crate("x")
.only_under(["crate::ffi", "crate::platform"])
.because("r");
assert_rule(
unsafe_confinement.rule_key(),
"tianheng.rule/hunyi/unsafe-confinement",
&[("allowed", "[\"crate::ffi\",\"crate::platform\"]")],
);
}
#[test]
pub(super) fn hunyi_rule_identity_is_set_order_stable_and_parameter_sensitive() {
let left = SignatureBoundary::in_crate("x")
.module("crate::api")
.must_not_expose("crate::infra")
.and_not_expose("crate::storage")
.because("first wording");
let reordered = SignatureBoundary::in_crate("other")
.module("crate::elsewhere")
.must_not_expose("crate::storage")
.and_not_expose("crate::infra")
.and_not_expose("crate::infra")
.warn()
.because("different wording")
.with_anchor("GOV-1");
let expanded = SignatureBoundary::in_crate("x")
.module("crate::api")
.must_not_expose("crate::infra")
.and_not_expose("crate::storage")
.and_not_expose("crate::transport")
.because("first wording");
let deeper = SignatureBoundary::in_crate("x")
.module("crate::api")
.must_not_expose("crate::infra")
.and_not_expose("crate::storage")
.including_trait_impls()
.because("first wording");
assert_eq!(left.rule_key(), reordered.rule_key());
assert_ne!(left.rule_key(), expanded.rule_key());
assert_ne!(left.rule_key(), deeper.rule_key());
}
#[test]
pub(super) fn a_glob_imported_type_in_an_impl_position_is_a_documented_coverage_bound() {
let globbed = super::helpers::findings_including_trait_impls(
"ti-glob-impl-pos",
&[
("lib.rs", "pub mod domain;\npub mod infra;\n"),
("infra.rs", "pub struct DbPool;\n"),
(
"domain.rs",
"use crate::infra::*;\npub struct Service;\nimpl From<DbPool> for Service {}\n",
),
],
"crate::domain",
&["crate::infra"],
)
.unwrap();
assert!(
globbed.is_empty(),
"a glob-imported type in an impl position is a documented bound: {globbed:?}"
);
let written = super::helpers::findings_including_trait_impls(
"ti-written-impl-pos",
&[
("lib.rs", "pub mod domain;\npub mod infra;\n"),
("infra.rs", "pub struct DbPool;\n"),
(
"domain.rs",
"pub struct Service;\nimpl From<crate::infra::DbPool> for Service {}\n",
),
],
"crate::domain",
&["crate::infra"],
)
.unwrap();
assert_eq!(
written.len(),
1,
"the control must react, or the empty result above says nothing: {written:?}"
);
}