Expand module-scoped use trees into exact import paths and bindings. Resolve renamed public symbols and module aliases without global-name fallback; keep unknown and block-local bindings conservative. Add positive and negative integration tests and an exact three-repeat import benchmark to the quality gate.
84 lines
2.6 KiB
Rust
84 lines
2.6 KiB
Rust
use brick::model::{EdgeKind, NodeKind};
|
|
use brick::scan;
|
|
use std::fs;
|
|
|
|
fn scan_files(files: &[(&str, &str)]) -> brick::Building {
|
|
let root = tempfile::tempdir().unwrap();
|
|
for (path, content) in files {
|
|
let file = root.path().join(path);
|
|
fs::create_dir_all(file.parent().unwrap()).unwrap();
|
|
fs::write(file, content).unwrap();
|
|
}
|
|
scan::scan(root.path()).unwrap()
|
|
}
|
|
|
|
fn target<'a>(model: &'a brick::Building, name: &str) -> &'a brick::model::Node {
|
|
let source = model
|
|
.nodes
|
|
.iter()
|
|
.find(|n| n.kind == NodeKind::Function && n.name == name)
|
|
.unwrap();
|
|
let edge = model
|
|
.edges
|
|
.iter()
|
|
.find(|e| e.kind == EdgeKind::Calls && e.source == source.id)
|
|
.unwrap();
|
|
model.nodes.iter().find(|n| n.id == edge.target).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn nested_groups_aliases_and_module_self_bindings_resolve_exactly() {
|
|
let model = scan_files(&[
|
|
(
|
|
"src/lib.rs",
|
|
"use crate::service::{self as svc, run as execute, nested::{stop}};\nfn a() { execute(); }\nfn b() { stop(); }\nfn c() { svc::run(); }",
|
|
),
|
|
("src/service.rs", "pub fn run() {}"),
|
|
("src/service/nested.rs", "pub fn stop() {}"),
|
|
("other/run.rs", "pub fn execute() {}"),
|
|
]);
|
|
for (source, path, name) in [
|
|
("a", "src/service.rs", "run"),
|
|
("b", "src/service/nested.rs", "stop"),
|
|
("c", "src/service.rs", "run"),
|
|
] {
|
|
let node = target(&model, source);
|
|
assert_eq!(node.path.as_deref(), Some(path));
|
|
assert_eq!(node.name, name);
|
|
}
|
|
assert!(!model.nodes.iter().any(|n| n.kind == NodeKind::External));
|
|
assert_eq!(
|
|
model
|
|
.edges
|
|
.iter()
|
|
.filter(|e| e.kind == EdgeKind::Imports)
|
|
.count(),
|
|
2
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn absent_private_wildcard_and_underscore_imports_cannot_authorize_calls() {
|
|
let model = scan_files(&[
|
|
(
|
|
"src/lib.rs",
|
|
"use crate::service::{hidden, run as _, *};\nuse crate::missing::{run as missing};\nfn a() { hidden(); }\nfn b() { run(); }\nfn c() { missing(); }",
|
|
),
|
|
("src/service.rs", "fn hidden() {}\npub fn run() {}"),
|
|
]);
|
|
for name in ["a", "b", "c"] {
|
|
assert_eq!(target(&model, name).kind, NodeKind::External);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn block_imports_do_not_leak_to_other_functions() {
|
|
let model = scan_files(&[
|
|
(
|
|
"src/lib.rs",
|
|
"fn a() { use crate::service::run as execute; execute(); }\nfn b() { execute(); }",
|
|
),
|
|
("src/service.rs", "pub fn run() {}"),
|
|
]);
|
|
assert_eq!(target(&model, "b").kind, NodeKind::External);
|
|
}
|