use super::{native_sources, native_sources_in, violations};
use crate::source_scan_tests::{classified_sources, real_roots, release_root, source_root, write_tree};
use crate::test_support::fixture;
fn scan(name: &str, files: &[(&str, &str)]) -> Result<Vec<String>, String> {
let root = fixture(name);
write_tree(&root, files);
let sources = native_sources_in(&root, &[release_root("lib.rs")])?;
return Ok(violations(sources.as_slice()));
}
#[test]
fn a_forbidden_import_in_a_nested_production_file_is_discovered_and_rejected() {
let found: Vec<String> = scan(
"boundary-scan-nested-production",
&[
("lib.rs", "mod forwarding;\nmod entry;\n"),
("forwarding/mod.rs", "mod extra;\n"),
("forwarding/extra.rs", "use super::super::standards_review_client::post_decision;\n"),
("entry/mod.rs", "mod agent;\n"),
("entry/agent.rs", "let agent = ureq::Agent::new_with_defaults();\n"),
],
)
.expect("a resolvable layout");
assert_eq!(
found,
vec![
String::from("entry/agent.rs names the HTTP library"),
String::from("forwarding/extra.rs names a service-only module"),
]
);
}
#[test]
fn a_nested_file_with_the_name_of_an_exempt_file_is_still_checked() {
let found: Vec<String> = scan(
"boundary-scan-exempt-name",
&[
("lib.rs", "mod standards_review;\nmod nested;\n"),
("standards_review/mod.rs", "mod standards_review_client;\nmod standards_review_run;\n"),
("standards_review/standards_review_client.rs", "let agent = ureq::Agent::new_with_defaults();\n"),
("standards_review/standards_review_run.rs", "use super::standards_review_client::post_decision;\n"),
("nested/mod.rs", "mod standards_review_client;\nmod standards_review_run;\n"),
("nested/standards_review_client.rs", "let agent = ureq::Agent::new_with_defaults();\n"),
("nested/standards_review_run.rs", "use crate::service_review::run;\n"),
],
)
.expect("a resolvable layout");
assert_eq!(
found,
vec![
String::from("nested/standards_review_client.rs names the HTTP library"),
String::from("nested/standards_review_run.rs names a service-only module"),
]
);
}
#[test]
fn a_module_declaration_in_a_nested_module_file_is_not_a_use() {
let found: Vec<String> = scan(
"boundary-scan-declaration",
&[
("lib.rs", "mod bridge;\n"),
("bridge/mod.rs", "mod standards_review_run;\n"),
("bridge/standards_review_run.rs", "// the run itself\n"),
],
)
.expect("a resolvable layout");
assert_eq!(found, Vec::<String>::new());
}
#[test]
fn a_use_beside_a_declaration_in_a_nested_module_file_is_rejected() {
let found: Vec<String> = scan(
"boundary-scan-use-beside-declaration",
&[
("lib.rs", "mod bridge;\n"),
("bridge/mod.rs", "mod standards_review_run;\nuse self::standards_review_run::run;\n"),
("bridge/standards_review_run.rs", "// the run itself\n"),
],
)
.expect("a resolvable layout");
assert_eq!(found, vec![String::from("bridge/mod.rs names a service-only module")]);
}
#[test]
fn a_declared_module_without_a_file_is_an_error() {
let outcome = scan("boundary-scan-missing-module", &[("lib.rs", "mod forwarding;\n")]);
assert!(outcome.is_err(), "{outcome:?}");
}
#[test]
fn a_source_file_no_declaration_reaches_is_an_error() {
let outcome = scan("boundary-scan-orphan", &[("lib.rs", ""), ("forwarding/forgotten.rs", "use ureq;\n")]);
let error: String = outcome.expect_err("an unreached file is an error");
assert!(error.contains("forwarding/forgotten.rs"), "{error}");
}
#[test]
fn a_tree_without_source_files_is_an_error() {
let outcome = scan("boundary-scan-empty", &[("notes.md", "no source here")]);
assert!(outcome.is_err(), "{outcome:?}");
}
#[cfg(unix)]
#[test]
fn a_link_in_the_tree_is_an_error() {
let root = fixture("boundary-scan-link");
write_tree(&root, &[("lib.rs", "")]);
std::os::unix::fs::symlink(root.join("nowhere.rs"), root.join("dangling.rs")).expect("a dangling link");
let outcome = native_sources_in(&root, &[release_root("lib.rs")]);
assert!(outcome.is_err(), "{outcome:?}");
}
#[test]
fn the_real_scan_reads_exactly_the_files_the_module_tree_reaches() {
let read: Vec<String> = native_sources().into_iter().map(|(path, _)| return path).collect();
let reached: Vec<String> = classified_sources(&source_root(), &real_roots())
.expect("the crate's own sources")
.into_iter()
.map(|file| return file.path)
.collect();
assert_eq!(read, reached);
}